From 6d9da5a4d04ff3d89455051132bc3d68ae97e155 Mon Sep 17 00:00:00 2001 From: Charlie Date: Fri, 13 Sep 2024 14:57:29 +0800 Subject: [PATCH] init --- .idea/.gitignore | 8 + .idea/modules.xml | 8 + .idea/sample-controller.iml | 9 + .idea/vcs.xml | 6 + .../.github/PULL_REQUEST_TEMPLATE.md | 2 + code-generator/CONTRIBUTING.md | 7 + code-generator/LICENSE | 202 ++ code-generator/OWNERS | 16 + code-generator/README.md | 29 + code-generator/SECURITY_CONTACTS | 16 + .../cmd/applyconfiguration-gen/args/args.go | 88 + .../args/externaltypes.go | 122 + .../generators/applyconfiguration.go | 479 +++ .../generators/internal.go | 101 + .../generators/jsontagutil.go | 99 + .../generators/openapi.go | 192 + .../generators/refgraph.go | 175 + .../generators/targets.go | 314 ++ .../generators/types.go | 37 + .../applyconfiguration-gen/generators/util.go | 176 + .../cmd/applyconfiguration-gen/main.go | 60 + code-generator/cmd/client-gen/OWNERS | 11 + code-generator/cmd/client-gen/README.md | 2 + code-generator/cmd/client-gen/args/args.go | 142 + .../cmd/client-gen/args/gvpackages.go | 175 + .../cmd/client-gen/args/gvpackages_test.go | 116 + code-generator/cmd/client-gen/args/gvtype.go | 110 + .../client-gen/generators/client_generator.go | 436 +++ .../generators/fake/fake_client_generator.go | 133 + .../fake/generator_fake_for_clientset.go | 218 ++ .../fake/generator_fake_for_group.go | 130 + .../fake/generator_fake_for_type.go | 587 ++++ .../generators/generator_for_clientset.go | 210 ++ .../generators/generator_for_expansion.go | 54 + .../generators/generator_for_group.go | 264 ++ .../generators/generator_for_type.go | 860 +++++ .../generators/scheme/generator_for_scheme.go | 187 + .../client-gen/generators/util/gvpackages.go | 30 + .../cmd/client-gen/generators/util/tags.go | 344 ++ .../client-gen/generators/util/tags_test.go | 148 + code-generator/cmd/client-gen/main.go | 67 + .../cmd/client-gen/types/helpers.go | 121 + .../cmd/client-gen/types/helpers_test.go | 32 + code-generator/cmd/client-gen/types/types.go | 109 + .../cmd/conversion-gen/args/args.go | 92 + .../conversion-gen/generators/conversion.go | 1207 +++++++ code-generator/cmd/conversion-gen/main.go | 137 + code-generator/cmd/deepcopy-gen/args/args.go | 52 + .../cmd/deepcopy-gen/generators/deepcopy.go | 892 +++++ .../deepcopy-gen/generators/deepcopy_test.go | 696 ++++ code-generator/cmd/deepcopy-gen/main.go | 110 + .../deepcopy-gen/output_tests/aliases/doc.go | 89 + .../aliases/zz_generated.deepcopy.go | 413 +++ .../deepcopy-gen/output_tests/builtins/doc.go | 35 + .../builtins/zz_generated.deepcopy.go | 38 + .../cmd/deepcopy-gen/output_tests/generate.go | 18 + .../output_tests/interface_fuzzer.go | 131 + .../output_tests/interfaces/doc.go | 29 + .../interfaces/zz_generated.deepcopy.go | 47 + .../cmd/deepcopy-gen/output_tests/maps/doc.go | 43 + .../maps/zz_generated.deepcopy.go | 243 ++ .../output_tests/otherpkg/interfaces.go | 25 + .../deepcopy-gen/output_tests/output_test.go | 173 + .../deepcopy-gen/output_tests/pointer/doc.go | 31 + .../pointer/zz_generated.deepcopy.go | 114 + .../output_tests/reflect_deepcopy.go | 81 + .../deepcopy-gen/output_tests/slices/doc.go | 43 + .../slices/zz_generated.deepcopy.go | 193 + .../deepcopy-gen/output_tests/structs/doc.go | 40 + .../structs/zz_generated.deepcopy.go | 56 + .../deepcopy-gen/output_tests/value_fuzzer.go | 86 + .../deepcopy-gen/output_tests/wholepkg/a.go | 171 + .../deepcopy-gen/output_tests/wholepkg/b.go | 20 + .../output_tests/wholepkg/deepcopy_test.go | 145 + .../deepcopy-gen/output_tests/wholepkg/doc.go | 20 + .../output_tests/wholepkg/interfaces.go | 21 + .../wholepkg/zz_generated.deepcopy.go | 761 ++++ code-generator/cmd/defaulter-gen/args/args.go | 53 + .../cmd/defaulter-gen/generators/defaulter.go | 1235 +++++++ code-generator/cmd/defaulter-gen/main.go | 83 + .../defaulter-gen/output_tests/empty/doc.go | 20 + .../defaulter-gen/output_tests/empty/type.go | 29 + .../empty/zz_generated.defaults.go | 33 + .../defaulter-gen/output_tests/generate.go | 27 + .../output_tests/marker/defaults.go | 32 + .../defaulter-gen/output_tests/marker/doc.go | 20 + .../output_tests/marker/external/constant.go | 20 + .../marker/external/external/constant.go | 20 + .../output_tests/marker/external2/type.go | 19 + .../output_tests/marker/external3/constant.go | 21 + .../marker/fake_deepcopy_conversion.go | 107 + .../output_tests/marker/marker_test.go | 412 +++ .../defaulter-gen/output_tests/marker/type.go | 265 ++ .../marker/zz_generated.defaults.go | 325 ++ .../output_tests/pointer/defaults.go | 33 + .../defaulter-gen/output_tests/pointer/doc.go | 20 + .../pointer/fake_deepcopy_conversion.go | 82 + .../output_tests/pointer/type.go | 33 + .../pointer/zz_generated.defaults.go | 46 + .../output_tests/slices/defaults.go | 33 + .../defaulter-gen/output_tests/slices/doc.go | 20 + .../slices/fake_deepcopy_conversion.go | 118 + .../defaulter-gen/output_tests/slices/type.go | 37 + .../slices/zz_generated.defaults.go | 56 + .../output_tests/wholepkg/defaults.go | 33 + .../output_tests/wholepkg/doc.go | 20 + .../wholepkg/fake_deepcopy_conversion.go | 315 ++ .../output_tests/wholepkg/type.go | 74 + .../wholepkg/zz_generated.defaults.go | 85 + code-generator/cmd/go-to-protobuf/.gitignore | 1 + code-generator/cmd/go-to-protobuf/OWNERS | 6 + code-generator/cmd/go-to-protobuf/main.go | 41 + .../cmd/go-to-protobuf/protobuf/cmd.go | 456 +++ .../cmd/go-to-protobuf/protobuf/cmd_test.go | 65 + .../cmd/go-to-protobuf/protobuf/generator.go | 777 ++++ .../go-to-protobuf/protobuf/import_tracker.go | 50 + .../cmd/go-to-protobuf/protobuf/namer.go | 206 ++ .../cmd/go-to-protobuf/protobuf/namer_test.go | 50 + .../cmd/go-to-protobuf/protobuf/package.go | 205 ++ .../cmd/go-to-protobuf/protobuf/parser.go | 453 +++ .../go-to-protobuf/protobuf/parser_test.go | 119 + .../cmd/go-to-protobuf/protobuf/tags.go | 33 + .../go-to-protobuf/protoc-gen-gogo/main.go | 51 + code-generator/cmd/informer-gen/args/args.go | 82 + .../cmd/informer-gen/generators/factory.go | 341 ++ .../generators/factoryinterface.go | 90 + .../cmd/informer-gen/generators/generic.go | 184 + .../informer-gen/generators/groupinterface.go | 118 + .../cmd/informer-gen/generators/informer.go | 187 + .../cmd/informer-gen/generators/targets.go | 373 ++ .../cmd/informer-gen/generators/types.go | 45 + .../generators/versioninterface.go | 109 + code-generator/cmd/informer-gen/main.go | 59 + code-generator/cmd/lister-gen/args/args.go | 62 + .../cmd/lister-gen/generators/expansion.go | 73 + .../cmd/lister-gen/generators/lister.go | 333 ++ code-generator/cmd/lister-gen/main.go | 59 + .../cmd/prerelease-lifecycle-gen/args/args.go | 50 + .../cmd/prerelease-lifecycle-gen/main.go | 76 + .../prerelease-lifecycle-generators/status.go | 497 +++ .../status_test.go | 798 +++++ code-generator/cmd/register-gen/args/args.go | 50 + .../generators/register_external.go | 117 + .../cmd/register-gen/generators/targets.go | 139 + code-generator/cmd/register-gen/main.go | 56 + code-generator/code-of-conduct.md | 3 + code-generator/doc.go | 17 + code-generator/examples/.gitignore | 2 + .../HyphenGroup/apis/example/v1/doc.go | 21 + .../HyphenGroup/apis/example/v1/register.go | 59 + .../HyphenGroup/apis/example/v1/types.go | 74 + .../apis/example/v1/zz_generated.deepcopy.go | 178 + .../apis/example/v1/zz_generated.defaults.go | 33 + .../example/v1/clustertesttype.go | 215 ++ .../example/v1/clustertesttypestatus.go | 39 + .../applyconfiguration/example/v1/testtype.go | 216 ++ .../example/v1/testtypestatus.go | 39 + .../applyconfiguration/internal/internal.go | 62 + .../HyphenGroup/applyconfiguration/utils.go | 50 + .../clientset/versioned/clientset.go | 16 +- .../versioned/fake/clientset_generated.go | 122 + .../clientset/versioned/fake/doc.go | 0 .../clientset/versioned/fake/register.go | 4 +- .../clientset/versioned/scheme/doc.go | 0 .../clientset/versioned/scheme/register.go | 4 +- .../typed/example/v1/clustertesttype.go | 104 + .../versioned/typed/example/v1}/doc.go | 2 +- .../typed/example/v1/example_client.go | 47 +- .../versioned/typed/example/v1}/fake/doc.go | 0 .../example/v1/fake/fake_clustertesttype.go | 209 ++ .../example/v1/fake/fake_example_client.go | 44 + .../typed/example/v1/fake/fake_testtype.go | 197 ++ .../typed/example/v1/generated_expansion.go | 23 + .../versioned/typed/example/v1/testtype.go | 73 + .../externalversions/example}/interface.go | 16 +- .../example/v1/clustertesttype.go | 89 + .../externalversions/example/v1/interface.go | 52 + .../externalversions/example/v1/testtype.go | 90 + .../informers/externalversions/factory.go | 12 +- .../informers/externalversions/generic.go | 64 + .../internalinterfaces/factory_interfaces.go | 40 + .../listers/example/v1/clustertesttype.go | 48 + .../listers/example/v1/expansion_generated.go | 31 + .../listers/example/v1/testtype.go | 70 + .../examples/MixedCase/apis/example/v1/doc.go | 20 + .../MixedCase/apis/example/v1/register.go | 59 + .../MixedCase/apis/example/v1/types.go | 76 + .../apis/example/v1/zz_generated.deepcopy.go | 178 + .../apis/example/v1/zz_generated.defaults.go | 33 + .../example/v1/clustertesttype.go | 215 ++ .../example/v1/clustertesttypestatus.go | 39 + .../applyconfiguration/example/v1/testtype.go | 216 ++ .../example/v1/testtypestatus.go | 39 + .../applyconfiguration/internal/internal.go | 62 + .../MixedCase/applyconfiguration/utils.go | 50 + .../clientset/versioned/clientset.go | 120 + .../versioned/fake/clientset_generated.go | 122 + .../MixedCase/clientset/versioned/fake/doc.go | 20 + .../clientset/versioned/fake/register.go | 56 + .../clientset/versioned/scheme/doc.go | 20 + .../clientset/versioned/scheme/register.go | 56 + .../typed/example/v1/clustertesttype.go | 119 + .../versioned/typed/example/v1/doc.go | 20 + .../typed/example/v1/example_client.go | 112 + .../versioned/typed/example/v1/fake/doc.go | 20 + .../example/v1/fake/fake_clustertesttype.go | 220 ++ .../example/v1/fake/fake_example_client.go | 44 + .../typed/example/v1/fake/fake_testtype.go | 197 ++ .../typed/example/v1/generated_expansion.go | 23 + .../versioned/typed/example/v1/testtype.go | 73 + .../externalversions/example/interface.go | 46 + .../example/v1/clustertesttype.go | 89 + .../externalversions/example/v1/interface.go | 52 + .../externalversions/example/v1/testtype.go | 90 + .../informers/externalversions/factory.go | 262 ++ .../informers/externalversions/generic.go | 64 + .../internalinterfaces/factory_interfaces.go | 40 + .../listers/example/v1/clustertesttype.go | 48 + .../listers/example/v1/expansion_generated.go | 31 + .../MixedCase/listers/example/v1/testtype.go | 70 + .../examples/apiserver/apis/core/doc.go | 20 + .../apiserver/apis/core/install/install.go | 33 + .../examples/apiserver/apis/core/register.go | 45 + .../examples/apiserver/apis/core/types.go | 47 + .../examples/apiserver/apis/core/v1/doc.go | 23 + .../apiserver/apis/core/v1/register.go | 59 + .../examples/apiserver/apis/core/v1/types.go | 47 + .../apis/core/v1/zz_generated.conversion.go | 138 + .../apis/core/v1/zz_generated.deepcopy.go | 102 + .../apis/core/v1/zz_generated.defaults.go | 33 + .../apis/core/zz_generated.deepcopy.go | 102 + .../examples/apiserver/apis/example/doc.go | 20 + .../apiserver/apis/example/install/install.go | 33 + .../apiserver/apis/example/register.go | 45 + .../examples/apiserver/apis/example/types.go | 47 + .../examples/apiserver/apis/example/v1/doc.go | 23 + .../apiserver/apis/example/v1/register.go | 59 + .../apiserver/apis/example/v1/types.go | 47 + .../example/v1/zz_generated.conversion.go | 138 + .../apis/example/v1/zz_generated.deepcopy.go | 102 + .../apis/example/v1/zz_generated.defaults.go | 33 + .../apis/example/zz_generated.deepcopy.go | 102 + .../examples/apiserver/apis/example2/doc.go | 21 + .../apis/example2/install/install.go | 33 + .../apiserver/apis/example2/register.go | 45 + .../examples/apiserver/apis/example2/types.go | 45 + .../apiserver/apis/example2/v1/doc.go | 24 + .../apiserver/apis/example2/v1/register.go | 59 + .../apiserver/apis/example2/v1/types.go | 47 + .../example2/v1/zz_generated.conversion.go | 138 + .../apis/example2/v1/zz_generated.deepcopy.go | 102 + .../apis/example2/v1/zz_generated.defaults.go | 33 + .../apis/example2/zz_generated.deepcopy.go | 102 + .../apiserver/apis/example3.io/doc.go | 21 + .../apis/example3.io/install/install.go | 33 + .../apiserver/apis/example3.io/register.go | 45 + .../apiserver/apis/example3.io/types.go | 47 + .../apiserver/apis/example3.io/v1/doc.go | 24 + .../apiserver/apis/example3.io/v1/register.go | 59 + .../apiserver/apis/example3.io/v1/types.go | 47 + .../example3.io/v1/zz_generated.conversion.go | 138 + .../example3.io/v1/zz_generated.deepcopy.go | 102 + .../example3.io/v1/zz_generated.defaults.go | 33 + .../apis/example3.io/zz_generated.deepcopy.go | 102 + .../clientset/versioned/clientset.go | 159 + .../versioned/fake/clientset_generated.go | 110 + .../apiserver/clientset/versioned/fake/doc.go | 20 + .../clientset/versioned/fake/register.go | 62 + .../clientset/versioned/scheme/doc.go | 20 + .../clientset/versioned/scheme/register.go | 62 + .../versioned/typed/core/v1/core_client.go | 107 + .../clientset/versioned/typed/core/v1/doc.go | 20 + .../versioned/typed/core/v1/fake/doc.go | 20 + .../typed/core/v1/fake/fake_core_client.go | 10 +- .../typed/core/v1/fake/fake_testtype.go | 147 + .../typed/core/v1}/generated_expansion.go | 4 +- .../versioned/typed/core/v1/testtype.go | 69 + .../versioned/typed/example/v1/doc.go | 20 + .../typed/example/v1/example_client.go | 107 + .../versioned/typed/example/v1/fake/doc.go | 20 + .../example/v1/fake/fake_example_client.go | 40 + .../typed/example/v1/fake/fake_testtype.go | 147 + .../typed/example/v1/generated_expansion.go | 21 + .../versioned/typed/example/v1/testtype.go | 69 + .../versioned/typed/example2/v1/doc.go | 20 + .../typed/example2/v1/example2_client.go | 107 + .../versioned/typed/example2/v1/fake/doc.go | 20 + .../example2/v1/fake/fake_example2_client.go | 40 + .../typed/example2/v1/fake/fake_testtype.go | 147 + .../typed/example2/v1/generated_expansion.go | 21 + .../versioned/typed/example2/v1/testtype.go | 69 + .../versioned/typed/example3.io/v1/doc.go | 20 + .../example3.io/v1/example3.io_client.go | 107 + .../typed/example3.io/v1/fake/doc.go | 20 + .../v1/fake/fake_example3.io_client.go | 40 + .../example3.io/v1/fake/fake_testtype.go | 147 + .../example3.io/v1/generated_expansion.go | 21 + .../typed/example3.io/v1/testtype.go | 69 + .../externalversions/core/interface.go | 46 + .../externalversions/core/v1/interface.go | 45 + .../externalversions/core/v1/testtype.go | 90 + .../externalversions/example/interface.go | 46 + .../externalversions/example/v1/interface.go | 45 + .../externalversions/example/v1/testtype.go | 90 + .../externalversions/example2/interface.go | 46 + .../externalversions/example2/v1/interface.go | 45 + .../externalversions/example2/v1/testtype.go | 90 + .../externalversions/example3.io/interface.go | 46 + .../example3.io/v1/interface.go | 45 + .../example3.io/v1/testtype.go | 90 + .../informers/externalversions/factory.go | 280 ++ .../informers/externalversions/generic.go | 77 + .../internalinterfaces/factory_interfaces.go | 40 + .../listers/core/v1/expansion_generated.go | 27 + .../apiserver/listers/core/v1/testtype.go | 70 + .../listers/example/v1/expansion_generated.go | 27 + .../apiserver/listers/example/v1/testtype.go | 70 + .../example2/v1}/expansion_generated.go | 10 +- .../apiserver/listers/example2/v1/testtype.go | 70 + .../listers/example2/v1/testtype_expansion.go | 31 + .../example3.io/v1/expansion_generated.go | 27 + .../listers/example3.io/v1/testtype.go | 70 + .../apiserver/openapi/zz_generated.openapi.go | 3127 +++++++++++++++++ .../examples/crd/apis/conflicting/v1/doc.go | 22 + .../crd/apis/conflicting/v1/register.go | 59 + .../examples/crd/apis/conflicting/v1/types.go | 56 + .../conflicting/v1}/zz_generated.deepcopy.go | 71 +- .../conflicting/v1/zz_generated.defaults.go | 33 + .../examples/crd/apis/example/v1/doc.go | 21 + .../examples/crd/apis/example/v1/register.go | 59 + .../examples/crd/apis/example/v1/types.go | 77 + .../apis/example/v1/zz_generated.deepcopy.go | 178 + .../apis/example/v1/zz_generated.defaults.go | 33 + .../examples/crd/apis/example2/v1/doc.go | 22 + .../examples/crd/apis/example2/v1/register.go | 59 + .../examples/crd/apis/example2/v1/types.go | 47 + .../apis/example2/v1/zz_generated.deepcopy.go | 102 + .../apis/example2/v1/zz_generated.defaults.go | 33 + .../conflicting/v1/testembeddedtype.go | 48 + .../conflicting/v1/testtype.go | 223 ++ .../conflicting/v1/testtypestatus.go | 39 + .../example/v1/clustertesttype.go | 215 ++ .../example/v1/clustertesttypestatus.go | 39 + .../applyconfiguration/example/v1/testtype.go | 216 ++ .../example/v1/testtypestatus.go | 39 + .../example2/v1/testtype.go | 216 ++ .../example2/v1/testtypestatus.go | 39 + .../applyconfiguration/internal/internal.go | 62 + .../examples/crd/applyconfiguration/utils.go | 68 + .../crd/clientset/versioned/clientset.go | 146 + .../versioned/fake/clientset_generated.go | 136 + .../crd/clientset/versioned/fake/doc.go | 20 + .../crd/clientset/versioned/fake/register.go | 60 + .../crd/clientset/versioned/scheme/doc.go | 20 + .../clientset/versioned/scheme/register.go | 60 + .../conflicting/v1/conflicting_client.go | 107 + .../versioned/typed/conflicting/v1/doc.go | 20 + .../typed/conflicting/v1/fake/doc.go | 20 + .../v1/fake/fake_conflicting_client.go | 40 + .../conflicting/v1/fake/fake_testtype.go | 197 ++ .../conflicting/v1/generated_expansion.go | 21 + .../typed/conflicting/v1/testtype.go | 73 + .../typed/example/v1/clustertesttype.go | 104 + .../versioned/typed/example/v1/doc.go | 20 + .../typed/example/v1/example_client.go | 112 + .../versioned/typed/example/v1/fake/doc.go | 20 + .../example/v1/fake/fake_clustertesttype.go | 209 ++ .../example/v1/fake/fake_example_client.go | 44 + .../typed/example/v1/fake/fake_testtype.go | 209 ++ .../typed/example/v1/generated_expansion.go | 23 + .../versioned/typed/example/v1/testtype.go | 88 + .../versioned/typed/example2/v1/doc.go | 20 + .../typed/example2/v1/example2_client.go | 107 + .../versioned/typed/example2/v1/fake/doc.go | 20 + .../example2/v1/fake/fake_example2_client.go | 40 + .../typed/example2/v1/fake/fake_testtype.go | 197 ++ .../typed/example2/v1/generated_expansion.go | 21 + .../versioned/typed/example2/v1/testtype.go | 73 + .../externalversions/conflicting/interface.go | 46 + .../conflicting/v1}/interface.go | 14 +- .../conflicting/v1/testtype.go | 90 + .../externalversions/example/interface.go | 46 + .../example/v1/clustertesttype.go | 89 + .../externalversions/example/v1/interface.go | 52 + .../externalversions/example/v1/testtype.go | 90 + .../externalversions/example2/interface.go | 46 + .../externalversions/example2/v1/interface.go | 45 + .../externalversions/example2/v1/testtype.go | 90 + .../crd/informers/externalversions/factory.go | 274 ++ .../crd/informers/externalversions/generic.go | 74 + .../internalinterfaces/factory_interfaces.go | 2 +- .../conflicting/v1/expansion_generated.go | 27 + .../crd/listers/conflicting/v1/testtype.go | 70 + .../crd/listers/example/v1/clustertesttype.go | 48 + .../listers/example/v1/expansion_generated.go | 31 + .../crd/listers/example/v1/testtype.go | 70 + .../example2/v1/expansion_generated.go | 27 + .../crd/listers/example2/v1/testtype.go | 70 + code-generator/examples/go.mod | 60 + code-generator/examples/go.sum | 151 + code-generator/examples/go.work | 8 + .../examples/hack/boilerplate.go.txt | 16 + .../examples/hack/update-codegen.sh | 86 + .../examples/hack/verify-codegen.sh | 54 + code-generator/examples/single/api/v1/doc.go | 21 + .../examples/single/api/v1/register.go | 59 + .../examples/single/api/v1/types.go | 75 + .../single/api/v1/zz_generated.deepcopy.go | 178 + .../single/api/v1/zz_generated.defaults.go | 33 + .../api/v1/clustertesttype.go | 215 ++ .../api/v1/clustertesttypestatus.go | 39 + .../applyconfiguration/api/v1/testtype.go | 216 ++ .../api/v1/testtypestatus.go | 39 + .../applyconfiguration/internal/internal.go | 62 + .../single/applyconfiguration/utils.go | 50 + .../single/clientset/versioned/clientset.go | 120 + .../versioned/fake/clientset_generated.go | 45 +- .../single/clientset/versioned/fake/doc.go | 20 + .../clientset/versioned/fake/register.go | 56 + .../single/clientset/versioned/scheme/doc.go | 20 + .../clientset/versioned/scheme/register.go | 56 + .../versioned/typed/api/v1/api_client.go | 112 + .../versioned/typed/api/v1/clustertesttype.go | 104 + .../clientset/versioned/typed/api/v1/doc.go | 20 + .../versioned/typed/api/v1/fake/doc.go | 20 + .../typed/api/v1/fake/fake_api_client.go | 44 + .../typed/api/v1/fake/fake_clustertesttype.go | 209 ++ .../typed/api/v1/fake/fake_testtype.go | 197 ++ .../typed/api/v1/generated_expansion.go | 23 + .../versioned/typed/api/v1/testtype.go | 73 + .../externalversions/api/interface.go | 46 + .../api/v1/clustertesttype.go | 89 + .../externalversions/api/v1/interface.go | 52 + .../externalversions/api/v1/testtype.go | 90 + .../informers/externalversions/factory.go | 262 ++ .../informers/externalversions/generic.go | 10 +- .../internalinterfaces/factory_interfaces.go | 40 + .../single/listers/api/v1/clustertesttype.go | 48 + .../listers/api/v1/expansion_generated.go | 31 + .../single/listers/api/v1/testtype.go | 70 + code-generator/generate-groups.sh | 20 + code-generator/generate-internal-groups.sh | 20 + code-generator/go.mod | 45 + code-generator/go.sum | 145 + code-generator/kube_codegen.sh | 759 ++++ code-generator/pkg/namer/tag-override.go | 59 + code-generator/pkg/util/plural_exceptions.go | 37 + .../third_party/forked/golang/LICENSE | 27 + .../third_party/forked/golang/PATENTS | 22 + .../third_party/forked/golang/reflect/type.go | 91 + code-generator/tools.go | 35 + code-generator/update-codegen.sh | 26 + controller.go | 10 +- go.mod | 2 +- main.go | 6 +- pkg/apis/samplecontroller/core/doc.go | 2 + pkg/apis/samplecontroller/core/register.go | 59 + pkg/apis/samplecontroller/core/types.go | 55 + pkg/apis/samplecontroller/v1alpha1/doc.go | 2 + .../samplecontroller/v1alpha1/register.go | 2 +- .../v1alpha1/fake/fake_foo.go | 147 - .../typed/samplecontroller/v1alpha1/foo.go | 69 - .../samplecontroller/v1alpha1/foo.go | 90 - .../listers/samplecontroller/v1alpha1/foo.go | 70 - 464 files changed, 47834 insertions(+), 506 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/modules.xml create mode 100644 .idea/sample-controller.iml create mode 100644 .idea/vcs.xml create mode 100644 code-generator/.github/PULL_REQUEST_TEMPLATE.md create mode 100644 code-generator/CONTRIBUTING.md create mode 100644 code-generator/LICENSE create mode 100644 code-generator/OWNERS create mode 100644 code-generator/README.md create mode 100644 code-generator/SECURITY_CONTACTS create mode 100644 code-generator/cmd/applyconfiguration-gen/args/args.go create mode 100644 code-generator/cmd/applyconfiguration-gen/args/externaltypes.go create mode 100644 code-generator/cmd/applyconfiguration-gen/generators/applyconfiguration.go create mode 100644 code-generator/cmd/applyconfiguration-gen/generators/internal.go create mode 100644 code-generator/cmd/applyconfiguration-gen/generators/jsontagutil.go create mode 100644 code-generator/cmd/applyconfiguration-gen/generators/openapi.go create mode 100644 code-generator/cmd/applyconfiguration-gen/generators/refgraph.go create mode 100644 code-generator/cmd/applyconfiguration-gen/generators/targets.go create mode 100644 code-generator/cmd/applyconfiguration-gen/generators/types.go create mode 100644 code-generator/cmd/applyconfiguration-gen/generators/util.go create mode 100644 code-generator/cmd/applyconfiguration-gen/main.go create mode 100644 code-generator/cmd/client-gen/OWNERS create mode 100644 code-generator/cmd/client-gen/README.md create mode 100644 code-generator/cmd/client-gen/args/args.go create mode 100644 code-generator/cmd/client-gen/args/gvpackages.go create mode 100644 code-generator/cmd/client-gen/args/gvpackages_test.go create mode 100644 code-generator/cmd/client-gen/args/gvtype.go create mode 100644 code-generator/cmd/client-gen/generators/client_generator.go create mode 100644 code-generator/cmd/client-gen/generators/fake/fake_client_generator.go create mode 100644 code-generator/cmd/client-gen/generators/fake/generator_fake_for_clientset.go create mode 100644 code-generator/cmd/client-gen/generators/fake/generator_fake_for_group.go create mode 100644 code-generator/cmd/client-gen/generators/fake/generator_fake_for_type.go create mode 100644 code-generator/cmd/client-gen/generators/generator_for_clientset.go create mode 100644 code-generator/cmd/client-gen/generators/generator_for_expansion.go create mode 100644 code-generator/cmd/client-gen/generators/generator_for_group.go create mode 100644 code-generator/cmd/client-gen/generators/generator_for_type.go create mode 100644 code-generator/cmd/client-gen/generators/scheme/generator_for_scheme.go create mode 100644 code-generator/cmd/client-gen/generators/util/gvpackages.go create mode 100644 code-generator/cmd/client-gen/generators/util/tags.go create mode 100644 code-generator/cmd/client-gen/generators/util/tags_test.go create mode 100644 code-generator/cmd/client-gen/main.go create mode 100644 code-generator/cmd/client-gen/types/helpers.go create mode 100644 code-generator/cmd/client-gen/types/helpers_test.go create mode 100644 code-generator/cmd/client-gen/types/types.go create mode 100644 code-generator/cmd/conversion-gen/args/args.go create mode 100644 code-generator/cmd/conversion-gen/generators/conversion.go create mode 100644 code-generator/cmd/conversion-gen/main.go create mode 100644 code-generator/cmd/deepcopy-gen/args/args.go create mode 100644 code-generator/cmd/deepcopy-gen/generators/deepcopy.go create mode 100644 code-generator/cmd/deepcopy-gen/generators/deepcopy_test.go create mode 100644 code-generator/cmd/deepcopy-gen/main.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/aliases/doc.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/aliases/zz_generated.deepcopy.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/builtins/doc.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/builtins/zz_generated.deepcopy.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/generate.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/interface_fuzzer.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/interfaces/doc.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/interfaces/zz_generated.deepcopy.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/maps/doc.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/maps/zz_generated.deepcopy.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/otherpkg/interfaces.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/output_test.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/pointer/doc.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/pointer/zz_generated.deepcopy.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/reflect_deepcopy.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/slices/doc.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/slices/zz_generated.deepcopy.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/structs/doc.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/structs/zz_generated.deepcopy.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/value_fuzzer.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/wholepkg/a.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/wholepkg/b.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/wholepkg/deepcopy_test.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/wholepkg/doc.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/wholepkg/interfaces.go create mode 100644 code-generator/cmd/deepcopy-gen/output_tests/wholepkg/zz_generated.deepcopy.go create mode 100644 code-generator/cmd/defaulter-gen/args/args.go create mode 100644 code-generator/cmd/defaulter-gen/generators/defaulter.go create mode 100644 code-generator/cmd/defaulter-gen/main.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/empty/doc.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/empty/type.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/empty/zz_generated.defaults.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/generate.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/marker/defaults.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/marker/doc.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/marker/external/constant.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/marker/external/external/constant.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/marker/external2/type.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/marker/external3/constant.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/marker/fake_deepcopy_conversion.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/marker/marker_test.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/marker/type.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/marker/zz_generated.defaults.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/pointer/defaults.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/pointer/doc.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/pointer/fake_deepcopy_conversion.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/pointer/type.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/pointer/zz_generated.defaults.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/slices/defaults.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/slices/doc.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/slices/fake_deepcopy_conversion.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/slices/type.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/slices/zz_generated.defaults.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/wholepkg/defaults.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/wholepkg/doc.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/wholepkg/fake_deepcopy_conversion.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/wholepkg/type.go create mode 100644 code-generator/cmd/defaulter-gen/output_tests/wholepkg/zz_generated.defaults.go create mode 100644 code-generator/cmd/go-to-protobuf/.gitignore create mode 100644 code-generator/cmd/go-to-protobuf/OWNERS create mode 100644 code-generator/cmd/go-to-protobuf/main.go create mode 100644 code-generator/cmd/go-to-protobuf/protobuf/cmd.go create mode 100644 code-generator/cmd/go-to-protobuf/protobuf/cmd_test.go create mode 100644 code-generator/cmd/go-to-protobuf/protobuf/generator.go create mode 100644 code-generator/cmd/go-to-protobuf/protobuf/import_tracker.go create mode 100644 code-generator/cmd/go-to-protobuf/protobuf/namer.go create mode 100644 code-generator/cmd/go-to-protobuf/protobuf/namer_test.go create mode 100644 code-generator/cmd/go-to-protobuf/protobuf/package.go create mode 100644 code-generator/cmd/go-to-protobuf/protobuf/parser.go create mode 100644 code-generator/cmd/go-to-protobuf/protobuf/parser_test.go create mode 100644 code-generator/cmd/go-to-protobuf/protobuf/tags.go create mode 100644 code-generator/cmd/go-to-protobuf/protoc-gen-gogo/main.go create mode 100644 code-generator/cmd/informer-gen/args/args.go create mode 100644 code-generator/cmd/informer-gen/generators/factory.go create mode 100644 code-generator/cmd/informer-gen/generators/factoryinterface.go create mode 100644 code-generator/cmd/informer-gen/generators/generic.go create mode 100644 code-generator/cmd/informer-gen/generators/groupinterface.go create mode 100644 code-generator/cmd/informer-gen/generators/informer.go create mode 100644 code-generator/cmd/informer-gen/generators/targets.go create mode 100644 code-generator/cmd/informer-gen/generators/types.go create mode 100644 code-generator/cmd/informer-gen/generators/versioninterface.go create mode 100644 code-generator/cmd/informer-gen/main.go create mode 100644 code-generator/cmd/lister-gen/args/args.go create mode 100644 code-generator/cmd/lister-gen/generators/expansion.go create mode 100644 code-generator/cmd/lister-gen/generators/lister.go create mode 100644 code-generator/cmd/lister-gen/main.go create mode 100644 code-generator/cmd/prerelease-lifecycle-gen/args/args.go create mode 100644 code-generator/cmd/prerelease-lifecycle-gen/main.go create mode 100644 code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators/status.go create mode 100644 code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators/status_test.go create mode 100644 code-generator/cmd/register-gen/args/args.go create mode 100644 code-generator/cmd/register-gen/generators/register_external.go create mode 100644 code-generator/cmd/register-gen/generators/targets.go create mode 100644 code-generator/cmd/register-gen/main.go create mode 100644 code-generator/code-of-conduct.md create mode 100644 code-generator/doc.go create mode 100644 code-generator/examples/.gitignore create mode 100644 code-generator/examples/HyphenGroup/apis/example/v1/doc.go create mode 100644 code-generator/examples/HyphenGroup/apis/example/v1/register.go create mode 100644 code-generator/examples/HyphenGroup/apis/example/v1/types.go create mode 100644 code-generator/examples/HyphenGroup/apis/example/v1/zz_generated.deepcopy.go create mode 100644 code-generator/examples/HyphenGroup/apis/example/v1/zz_generated.defaults.go create mode 100644 code-generator/examples/HyphenGroup/applyconfiguration/example/v1/clustertesttype.go create mode 100644 code-generator/examples/HyphenGroup/applyconfiguration/example/v1/clustertesttypestatus.go create mode 100644 code-generator/examples/HyphenGroup/applyconfiguration/example/v1/testtype.go create mode 100644 code-generator/examples/HyphenGroup/applyconfiguration/example/v1/testtypestatus.go create mode 100644 code-generator/examples/HyphenGroup/applyconfiguration/internal/internal.go create mode 100644 code-generator/examples/HyphenGroup/applyconfiguration/utils.go rename {pkg/generated => code-generator/examples/HyphenGroup}/clientset/versioned/clientset.go (82%) create mode 100644 code-generator/examples/HyphenGroup/clientset/versioned/fake/clientset_generated.go rename {pkg/generated => code-generator/examples/HyphenGroup}/clientset/versioned/fake/doc.go (100%) rename {pkg/generated => code-generator/examples/HyphenGroup}/clientset/versioned/fake/register.go (93%) rename {pkg/generated => code-generator/examples/HyphenGroup}/clientset/versioned/scheme/doc.go (100%) rename {pkg/generated => code-generator/examples/HyphenGroup}/clientset/versioned/scheme/register.go (93%) create mode 100644 code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/clustertesttype.go rename {pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1 => code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1}/doc.go (97%) rename pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/samplecontroller_client.go => code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/example_client.go (58%) rename {pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1 => code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1}/fake/doc.go (100%) create mode 100644 code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go create mode 100644 code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/fake/fake_example_client.go create mode 100644 code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/fake/fake_testtype.go create mode 100644 code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/generated_expansion.go create mode 100644 code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/testtype.go rename {pkg/generated/informers/externalversions/samplecontroller => code-generator/examples/HyphenGroup/informers/externalversions/example}/interface.go (69%) create mode 100644 code-generator/examples/HyphenGroup/informers/externalversions/example/v1/clustertesttype.go create mode 100644 code-generator/examples/HyphenGroup/informers/externalversions/example/v1/interface.go create mode 100644 code-generator/examples/HyphenGroup/informers/externalversions/example/v1/testtype.go rename {pkg/generated => code-generator/examples/HyphenGroup}/informers/externalversions/factory.go (94%) create mode 100644 code-generator/examples/HyphenGroup/informers/externalversions/generic.go create mode 100644 code-generator/examples/HyphenGroup/informers/externalversions/internalinterfaces/factory_interfaces.go create mode 100644 code-generator/examples/HyphenGroup/listers/example/v1/clustertesttype.go create mode 100644 code-generator/examples/HyphenGroup/listers/example/v1/expansion_generated.go create mode 100644 code-generator/examples/HyphenGroup/listers/example/v1/testtype.go create mode 100644 code-generator/examples/MixedCase/apis/example/v1/doc.go create mode 100644 code-generator/examples/MixedCase/apis/example/v1/register.go create mode 100644 code-generator/examples/MixedCase/apis/example/v1/types.go create mode 100644 code-generator/examples/MixedCase/apis/example/v1/zz_generated.deepcopy.go create mode 100644 code-generator/examples/MixedCase/apis/example/v1/zz_generated.defaults.go create mode 100644 code-generator/examples/MixedCase/applyconfiguration/example/v1/clustertesttype.go create mode 100644 code-generator/examples/MixedCase/applyconfiguration/example/v1/clustertesttypestatus.go create mode 100644 code-generator/examples/MixedCase/applyconfiguration/example/v1/testtype.go create mode 100644 code-generator/examples/MixedCase/applyconfiguration/example/v1/testtypestatus.go create mode 100644 code-generator/examples/MixedCase/applyconfiguration/internal/internal.go create mode 100644 code-generator/examples/MixedCase/applyconfiguration/utils.go create mode 100644 code-generator/examples/MixedCase/clientset/versioned/clientset.go create mode 100644 code-generator/examples/MixedCase/clientset/versioned/fake/clientset_generated.go create mode 100644 code-generator/examples/MixedCase/clientset/versioned/fake/doc.go create mode 100644 code-generator/examples/MixedCase/clientset/versioned/fake/register.go create mode 100644 code-generator/examples/MixedCase/clientset/versioned/scheme/doc.go create mode 100644 code-generator/examples/MixedCase/clientset/versioned/scheme/register.go create mode 100644 code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/clustertesttype.go create mode 100644 code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/doc.go create mode 100644 code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/example_client.go create mode 100644 code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/fake/doc.go create mode 100644 code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go create mode 100644 code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_example_client.go create mode 100644 code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_testtype.go create mode 100644 code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/generated_expansion.go create mode 100644 code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/testtype.go create mode 100644 code-generator/examples/MixedCase/informers/externalversions/example/interface.go create mode 100644 code-generator/examples/MixedCase/informers/externalversions/example/v1/clustertesttype.go create mode 100644 code-generator/examples/MixedCase/informers/externalversions/example/v1/interface.go create mode 100644 code-generator/examples/MixedCase/informers/externalversions/example/v1/testtype.go create mode 100644 code-generator/examples/MixedCase/informers/externalversions/factory.go create mode 100644 code-generator/examples/MixedCase/informers/externalversions/generic.go create mode 100644 code-generator/examples/MixedCase/informers/externalversions/internalinterfaces/factory_interfaces.go create mode 100644 code-generator/examples/MixedCase/listers/example/v1/clustertesttype.go create mode 100644 code-generator/examples/MixedCase/listers/example/v1/expansion_generated.go create mode 100644 code-generator/examples/MixedCase/listers/example/v1/testtype.go create mode 100644 code-generator/examples/apiserver/apis/core/doc.go create mode 100644 code-generator/examples/apiserver/apis/core/install/install.go create mode 100644 code-generator/examples/apiserver/apis/core/register.go create mode 100644 code-generator/examples/apiserver/apis/core/types.go create mode 100644 code-generator/examples/apiserver/apis/core/v1/doc.go create mode 100644 code-generator/examples/apiserver/apis/core/v1/register.go create mode 100644 code-generator/examples/apiserver/apis/core/v1/types.go create mode 100644 code-generator/examples/apiserver/apis/core/v1/zz_generated.conversion.go create mode 100644 code-generator/examples/apiserver/apis/core/v1/zz_generated.deepcopy.go create mode 100644 code-generator/examples/apiserver/apis/core/v1/zz_generated.defaults.go create mode 100644 code-generator/examples/apiserver/apis/core/zz_generated.deepcopy.go create mode 100644 code-generator/examples/apiserver/apis/example/doc.go create mode 100644 code-generator/examples/apiserver/apis/example/install/install.go create mode 100644 code-generator/examples/apiserver/apis/example/register.go create mode 100644 code-generator/examples/apiserver/apis/example/types.go create mode 100644 code-generator/examples/apiserver/apis/example/v1/doc.go create mode 100644 code-generator/examples/apiserver/apis/example/v1/register.go create mode 100644 code-generator/examples/apiserver/apis/example/v1/types.go create mode 100644 code-generator/examples/apiserver/apis/example/v1/zz_generated.conversion.go create mode 100644 code-generator/examples/apiserver/apis/example/v1/zz_generated.deepcopy.go create mode 100644 code-generator/examples/apiserver/apis/example/v1/zz_generated.defaults.go create mode 100644 code-generator/examples/apiserver/apis/example/zz_generated.deepcopy.go create mode 100644 code-generator/examples/apiserver/apis/example2/doc.go create mode 100644 code-generator/examples/apiserver/apis/example2/install/install.go create mode 100644 code-generator/examples/apiserver/apis/example2/register.go create mode 100644 code-generator/examples/apiserver/apis/example2/types.go create mode 100644 code-generator/examples/apiserver/apis/example2/v1/doc.go create mode 100644 code-generator/examples/apiserver/apis/example2/v1/register.go create mode 100644 code-generator/examples/apiserver/apis/example2/v1/types.go create mode 100644 code-generator/examples/apiserver/apis/example2/v1/zz_generated.conversion.go create mode 100644 code-generator/examples/apiserver/apis/example2/v1/zz_generated.deepcopy.go create mode 100644 code-generator/examples/apiserver/apis/example2/v1/zz_generated.defaults.go create mode 100644 code-generator/examples/apiserver/apis/example2/zz_generated.deepcopy.go create mode 100644 code-generator/examples/apiserver/apis/example3.io/doc.go create mode 100644 code-generator/examples/apiserver/apis/example3.io/install/install.go create mode 100644 code-generator/examples/apiserver/apis/example3.io/register.go create mode 100644 code-generator/examples/apiserver/apis/example3.io/types.go create mode 100644 code-generator/examples/apiserver/apis/example3.io/v1/doc.go create mode 100644 code-generator/examples/apiserver/apis/example3.io/v1/register.go create mode 100644 code-generator/examples/apiserver/apis/example3.io/v1/types.go create mode 100644 code-generator/examples/apiserver/apis/example3.io/v1/zz_generated.conversion.go create mode 100644 code-generator/examples/apiserver/apis/example3.io/v1/zz_generated.deepcopy.go create mode 100644 code-generator/examples/apiserver/apis/example3.io/v1/zz_generated.defaults.go create mode 100644 code-generator/examples/apiserver/apis/example3.io/zz_generated.deepcopy.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/clientset.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/fake/clientset_generated.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/fake/doc.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/fake/register.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/scheme/doc.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/scheme/register.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/core/v1/core_client.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/core/v1/doc.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/core/v1/fake/doc.go rename pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/fake/fake_samplecontroller_client.go => code-generator/examples/apiserver/clientset/versioned/typed/core/v1/fake/fake_core_client.go (72%) create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/core/v1/fake/fake_testtype.go rename {pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1 => code-generator/examples/apiserver/clientset/versioned/typed/core/v1}/generated_expansion.go (92%) create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/core/v1/testtype.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example/v1/doc.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example/v1/example_client.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example/v1/fake/doc.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_example_client.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_testtype.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example/v1/generated_expansion.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example/v1/testtype.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/doc.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/example2_client.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/fake/doc.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_testtype.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/generated_expansion.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/testtype.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/doc.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/example3.io_client.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/fake/doc.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/fake/fake_example3.io_client.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/fake/fake_testtype.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/generated_expansion.go create mode 100644 code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/testtype.go create mode 100644 code-generator/examples/apiserver/informers/externalversions/core/interface.go create mode 100644 code-generator/examples/apiserver/informers/externalversions/core/v1/interface.go create mode 100644 code-generator/examples/apiserver/informers/externalversions/core/v1/testtype.go create mode 100644 code-generator/examples/apiserver/informers/externalversions/example/interface.go create mode 100644 code-generator/examples/apiserver/informers/externalversions/example/v1/interface.go create mode 100644 code-generator/examples/apiserver/informers/externalversions/example/v1/testtype.go create mode 100644 code-generator/examples/apiserver/informers/externalversions/example2/interface.go create mode 100644 code-generator/examples/apiserver/informers/externalversions/example2/v1/interface.go create mode 100644 code-generator/examples/apiserver/informers/externalversions/example2/v1/testtype.go create mode 100644 code-generator/examples/apiserver/informers/externalversions/example3.io/interface.go create mode 100644 code-generator/examples/apiserver/informers/externalversions/example3.io/v1/interface.go create mode 100644 code-generator/examples/apiserver/informers/externalversions/example3.io/v1/testtype.go create mode 100644 code-generator/examples/apiserver/informers/externalversions/factory.go create mode 100644 code-generator/examples/apiserver/informers/externalversions/generic.go create mode 100644 code-generator/examples/apiserver/informers/externalversions/internalinterfaces/factory_interfaces.go create mode 100644 code-generator/examples/apiserver/listers/core/v1/expansion_generated.go create mode 100644 code-generator/examples/apiserver/listers/core/v1/testtype.go create mode 100644 code-generator/examples/apiserver/listers/example/v1/expansion_generated.go create mode 100644 code-generator/examples/apiserver/listers/example/v1/testtype.go rename {pkg/generated/listers/samplecontroller/v1alpha1 => code-generator/examples/apiserver/listers/example2/v1}/expansion_generated.go (69%) create mode 100644 code-generator/examples/apiserver/listers/example2/v1/testtype.go create mode 100644 code-generator/examples/apiserver/listers/example2/v1/testtype_expansion.go create mode 100644 code-generator/examples/apiserver/listers/example3.io/v1/expansion_generated.go create mode 100644 code-generator/examples/apiserver/listers/example3.io/v1/testtype.go create mode 100644 code-generator/examples/apiserver/openapi/zz_generated.openapi.go create mode 100644 code-generator/examples/crd/apis/conflicting/v1/doc.go create mode 100644 code-generator/examples/crd/apis/conflicting/v1/register.go create mode 100644 code-generator/examples/crd/apis/conflicting/v1/types.go rename {pkg/apis/samplecontroller/v1alpha1 => code-generator/examples/crd/apis/conflicting/v1}/zz_generated.deepcopy.go (73%) create mode 100644 code-generator/examples/crd/apis/conflicting/v1/zz_generated.defaults.go create mode 100644 code-generator/examples/crd/apis/example/v1/doc.go create mode 100644 code-generator/examples/crd/apis/example/v1/register.go create mode 100644 code-generator/examples/crd/apis/example/v1/types.go create mode 100644 code-generator/examples/crd/apis/example/v1/zz_generated.deepcopy.go create mode 100644 code-generator/examples/crd/apis/example/v1/zz_generated.defaults.go create mode 100644 code-generator/examples/crd/apis/example2/v1/doc.go create mode 100644 code-generator/examples/crd/apis/example2/v1/register.go create mode 100644 code-generator/examples/crd/apis/example2/v1/types.go create mode 100644 code-generator/examples/crd/apis/example2/v1/zz_generated.deepcopy.go create mode 100644 code-generator/examples/crd/apis/example2/v1/zz_generated.defaults.go create mode 100644 code-generator/examples/crd/applyconfiguration/conflicting/v1/testembeddedtype.go create mode 100644 code-generator/examples/crd/applyconfiguration/conflicting/v1/testtype.go create mode 100644 code-generator/examples/crd/applyconfiguration/conflicting/v1/testtypestatus.go create mode 100644 code-generator/examples/crd/applyconfiguration/example/v1/clustertesttype.go create mode 100644 code-generator/examples/crd/applyconfiguration/example/v1/clustertesttypestatus.go create mode 100644 code-generator/examples/crd/applyconfiguration/example/v1/testtype.go create mode 100644 code-generator/examples/crd/applyconfiguration/example/v1/testtypestatus.go create mode 100644 code-generator/examples/crd/applyconfiguration/example2/v1/testtype.go create mode 100644 code-generator/examples/crd/applyconfiguration/example2/v1/testtypestatus.go create mode 100644 code-generator/examples/crd/applyconfiguration/internal/internal.go create mode 100644 code-generator/examples/crd/applyconfiguration/utils.go create mode 100644 code-generator/examples/crd/clientset/versioned/clientset.go create mode 100644 code-generator/examples/crd/clientset/versioned/fake/clientset_generated.go create mode 100644 code-generator/examples/crd/clientset/versioned/fake/doc.go create mode 100644 code-generator/examples/crd/clientset/versioned/fake/register.go create mode 100644 code-generator/examples/crd/clientset/versioned/scheme/doc.go create mode 100644 code-generator/examples/crd/clientset/versioned/scheme/register.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/conflicting_client.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/doc.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/fake/doc.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/fake/fake_conflicting_client.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/fake/fake_testtype.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/generated_expansion.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/testtype.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/example/v1/clustertesttype.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/example/v1/doc.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/example/v1/example_client.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/example/v1/fake/doc.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/example/v1/fake/fake_example_client.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/example/v1/fake/fake_testtype.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/example/v1/generated_expansion.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/example/v1/testtype.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/example2/v1/doc.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/example2/v1/example2_client.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/example2/v1/fake/doc.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/example2/v1/fake/fake_testtype.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/example2/v1/generated_expansion.go create mode 100644 code-generator/examples/crd/clientset/versioned/typed/example2/v1/testtype.go create mode 100644 code-generator/examples/crd/informers/externalversions/conflicting/interface.go rename {pkg/generated/informers/externalversions/samplecontroller/v1alpha1 => code-generator/examples/crd/informers/externalversions/conflicting/v1}/interface.go (75%) create mode 100644 code-generator/examples/crd/informers/externalversions/conflicting/v1/testtype.go create mode 100644 code-generator/examples/crd/informers/externalversions/example/interface.go create mode 100644 code-generator/examples/crd/informers/externalversions/example/v1/clustertesttype.go create mode 100644 code-generator/examples/crd/informers/externalversions/example/v1/interface.go create mode 100644 code-generator/examples/crd/informers/externalversions/example/v1/testtype.go create mode 100644 code-generator/examples/crd/informers/externalversions/example2/interface.go create mode 100644 code-generator/examples/crd/informers/externalversions/example2/v1/interface.go create mode 100644 code-generator/examples/crd/informers/externalversions/example2/v1/testtype.go create mode 100644 code-generator/examples/crd/informers/externalversions/factory.go create mode 100644 code-generator/examples/crd/informers/externalversions/generic.go rename {pkg/generated => code-generator/examples/crd}/informers/externalversions/internalinterfaces/factory_interfaces.go (94%) create mode 100644 code-generator/examples/crd/listers/conflicting/v1/expansion_generated.go create mode 100644 code-generator/examples/crd/listers/conflicting/v1/testtype.go create mode 100644 code-generator/examples/crd/listers/example/v1/clustertesttype.go create mode 100644 code-generator/examples/crd/listers/example/v1/expansion_generated.go create mode 100644 code-generator/examples/crd/listers/example/v1/testtype.go create mode 100644 code-generator/examples/crd/listers/example2/v1/expansion_generated.go create mode 100644 code-generator/examples/crd/listers/example2/v1/testtype.go create mode 100644 code-generator/examples/go.mod create mode 100644 code-generator/examples/go.sum create mode 100644 code-generator/examples/go.work create mode 100644 code-generator/examples/hack/boilerplate.go.txt create mode 100755 code-generator/examples/hack/update-codegen.sh create mode 100755 code-generator/examples/hack/verify-codegen.sh create mode 100644 code-generator/examples/single/api/v1/doc.go create mode 100644 code-generator/examples/single/api/v1/register.go create mode 100644 code-generator/examples/single/api/v1/types.go create mode 100644 code-generator/examples/single/api/v1/zz_generated.deepcopy.go create mode 100644 code-generator/examples/single/api/v1/zz_generated.defaults.go create mode 100644 code-generator/examples/single/applyconfiguration/api/v1/clustertesttype.go create mode 100644 code-generator/examples/single/applyconfiguration/api/v1/clustertesttypestatus.go create mode 100644 code-generator/examples/single/applyconfiguration/api/v1/testtype.go create mode 100644 code-generator/examples/single/applyconfiguration/api/v1/testtypestatus.go create mode 100644 code-generator/examples/single/applyconfiguration/internal/internal.go create mode 100644 code-generator/examples/single/applyconfiguration/utils.go create mode 100644 code-generator/examples/single/clientset/versioned/clientset.go rename {pkg/generated => code-generator/examples/single}/clientset/versioned/fake/clientset_generated.go (62%) create mode 100644 code-generator/examples/single/clientset/versioned/fake/doc.go create mode 100644 code-generator/examples/single/clientset/versioned/fake/register.go create mode 100644 code-generator/examples/single/clientset/versioned/scheme/doc.go create mode 100644 code-generator/examples/single/clientset/versioned/scheme/register.go create mode 100644 code-generator/examples/single/clientset/versioned/typed/api/v1/api_client.go create mode 100644 code-generator/examples/single/clientset/versioned/typed/api/v1/clustertesttype.go create mode 100644 code-generator/examples/single/clientset/versioned/typed/api/v1/doc.go create mode 100644 code-generator/examples/single/clientset/versioned/typed/api/v1/fake/doc.go create mode 100644 code-generator/examples/single/clientset/versioned/typed/api/v1/fake/fake_api_client.go create mode 100644 code-generator/examples/single/clientset/versioned/typed/api/v1/fake/fake_clustertesttype.go create mode 100644 code-generator/examples/single/clientset/versioned/typed/api/v1/fake/fake_testtype.go create mode 100644 code-generator/examples/single/clientset/versioned/typed/api/v1/generated_expansion.go create mode 100644 code-generator/examples/single/clientset/versioned/typed/api/v1/testtype.go create mode 100644 code-generator/examples/single/informers/externalversions/api/interface.go create mode 100644 code-generator/examples/single/informers/externalversions/api/v1/clustertesttype.go create mode 100644 code-generator/examples/single/informers/externalversions/api/v1/interface.go create mode 100644 code-generator/examples/single/informers/externalversions/api/v1/testtype.go create mode 100644 code-generator/examples/single/informers/externalversions/factory.go rename {pkg/generated => code-generator/examples/single}/informers/externalversions/generic.go (81%) create mode 100644 code-generator/examples/single/informers/externalversions/internalinterfaces/factory_interfaces.go create mode 100644 code-generator/examples/single/listers/api/v1/clustertesttype.go create mode 100644 code-generator/examples/single/listers/api/v1/expansion_generated.go create mode 100644 code-generator/examples/single/listers/api/v1/testtype.go create mode 100755 code-generator/generate-groups.sh create mode 100755 code-generator/generate-internal-groups.sh create mode 100644 code-generator/go.mod create mode 100644 code-generator/go.sum create mode 100755 code-generator/kube_codegen.sh create mode 100644 code-generator/pkg/namer/tag-override.go create mode 100644 code-generator/pkg/util/plural_exceptions.go create mode 100644 code-generator/third_party/forked/golang/LICENSE create mode 100644 code-generator/third_party/forked/golang/PATENTS create mode 100644 code-generator/third_party/forked/golang/reflect/type.go create mode 100644 code-generator/tools.go create mode 100755 code-generator/update-codegen.sh create mode 100644 pkg/apis/samplecontroller/core/doc.go create mode 100644 pkg/apis/samplecontroller/core/register.go create mode 100644 pkg/apis/samplecontroller/core/types.go delete mode 100644 pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/fake/fake_foo.go delete mode 100644 pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/foo.go delete mode 100644 pkg/generated/informers/externalversions/samplecontroller/v1alpha1/foo.go delete mode 100644 pkg/generated/listers/samplecontroller/v1alpha1/foo.go diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..13566b81b --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..ccd336bec --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/sample-controller.iml b/.idea/sample-controller.iml new file mode 100644 index 000000000..5e764c4f0 --- /dev/null +++ b/.idea/sample-controller.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..94a25f7f4 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/code-generator/.github/PULL_REQUEST_TEMPLATE.md b/code-generator/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..e7e5eb834 --- /dev/null +++ b/code-generator/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,2 @@ +Sorry, we do not accept changes directly against this repository. Please see +CONTRIBUTING.md for information on where and how to contribute instead. diff --git a/code-generator/CONTRIBUTING.md b/code-generator/CONTRIBUTING.md new file mode 100644 index 000000000..76625b7bc --- /dev/null +++ b/code-generator/CONTRIBUTING.md @@ -0,0 +1,7 @@ +# Contributing guidelines + +Do not open pull requests directly against this repository, they will be ignored. Instead, please open pull requests against [kubernetes/kubernetes](https://git.k8s.io/kubernetes/). Please follow the same [contributing guide](https://git.k8s.io/kubernetes/CONTRIBUTING.md) you would follow for any other pull request made to kubernetes/kubernetes. + +This repository is published from [kubernetes/kubernetes/staging/src/k8s.io/code-generator](https://git.k8s.io/kubernetes/staging/src/k8s.io/code-generator) by the [kubernetes publishing-bot](https://git.k8s.io/publishing-bot). + +Please see [Staging Directory and Publishing](https://git.k8s.io/community/contributors/devel/sig-architecture/staging.md) for more information diff --git a/code-generator/LICENSE b/code-generator/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/code-generator/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/code-generator/OWNERS b/code-generator/OWNERS new file mode 100644 index 000000000..d16e47e85 --- /dev/null +++ b/code-generator/OWNERS @@ -0,0 +1,16 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +approvers: + - deads2k + - jpbetz + - wojtek-t + - sttts +reviewers: + - deads2k + - wojtek-t + - sttts +labels: + - sig/api-machinery + - area/code-generation +emeritus_approvers: + - lavalamp diff --git a/code-generator/README.md b/code-generator/README.md new file mode 100644 index 000000000..b0055265e --- /dev/null +++ b/code-generator/README.md @@ -0,0 +1,29 @@ +# code-generator + +Golang code-generators used to implement [Kubernetes-style API types](https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md). + +## Purpose + +These code-generators can be used +- in the context of [CustomResourceDefinition](https://kubernetes.io/docs/tasks/access-kubernetes-api/extend-api-custom-resource-definitions/) to build native, versioned clients, + informers and other helpers +- in the context of [User-provider API Servers](https://github.com/kubernetes/apiserver) to build conversions between internal and versioned types, defaulters, protobuf codecs, + internal and versioned clients and informers. + +## Resources +- The example [sample controller](https://github.com/kubernetes/sample-controller) shows a code example of a controller that uses the clients, listers and informers generated by this library. +- The article [Kubernetes Deep Dive: Code Generation for CustomResources](https://cloud.redhat.com/blog/kubernetes-deep-dive-code-generation-customresources/) gives a step by step instruction on how to use this library. + +## Usage + +The examples above are dated. The current recommended script to use is [kube_codegen.sh](kube_codegen.sh). + +## Compatibility + +HEAD of this repo will match HEAD of k8s.io/apiserver, k8s.io/apimachinery, and k8s.io/client-go. + +## Where does it come from? + +`code-generator` is synced from https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/code-generator. +Code changes are made in that location, merged into `k8s.io/kubernetes` and later synced here. + diff --git a/code-generator/SECURITY_CONTACTS b/code-generator/SECURITY_CONTACTS new file mode 100644 index 000000000..f6003980f --- /dev/null +++ b/code-generator/SECURITY_CONTACTS @@ -0,0 +1,16 @@ +# Defined below are the security contacts for this repo. +# +# They are the contact point for the Product Security Committee to reach out +# to for triaging and handling of incoming issues. +# +# The below names agree to abide by the +# [Embargo Policy](https://git.k8s.io/security/private-distributors-list.md#embargo-policy) +# and will be removed and replaced if they violate that agreement. +# +# DO NOT REPORT SECURITY VULNERABILITIES DIRECTLY TO THESE NAMES, FOLLOW THE +# INSTRUCTIONS AT https://kubernetes.io/security/ + +cheftako +deads2k +lavalamp +sttts diff --git a/code-generator/cmd/applyconfiguration-gen/args/args.go b/code-generator/cmd/applyconfiguration-gen/args/args.go new file mode 100644 index 000000000..36aa7a371 --- /dev/null +++ b/code-generator/cmd/applyconfiguration-gen/args/args.go @@ -0,0 +1,88 @@ +/* +Copyright 2021 The Kubernetes 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/v2/types" +) + +// Args is a wrapper for arguments to applyconfiguration-gen. +type Args struct { + OutputDir string // must be a directory path + OutputPkg string // must be a Go import-path + + GoHeaderFile string + + // ExternalApplyConfigurations provides the locations of externally generated + // apply configuration types for types referenced by the go structs provided as input. + // Locations are provided as a comma separated list of .: + // entries. + // + // E.g. if a type references appsv1.Deployment, the location of its apply configuration should + // be provided: + // k8s.io/api/apps/v1.Deployment:k8s.io/client-go/applyconfigurations/apps/v1 + // + // meta/v1 types (TypeMeta and ObjectMeta) are always included and do not need to be passed in. + ExternalApplyConfigurations map[types.Name]string + + OpenAPISchemaFilePath string +} + +// New returns default arguments for the generator. +func New() *Args { + return &Args{ + ExternalApplyConfigurations: map[types.Name]string{ + // Always include the applyconfigurations we've generated in client-go. They are sufficient for the vast majority of use cases. + {Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "Condition"}: "k8s.io/client-go/applyconfigurations/meta/v1", + {Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}: "k8s.io/client-go/applyconfigurations/meta/v1", + {Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "LabelSelector"}: "k8s.io/client-go/applyconfigurations/meta/v1", + {Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "LabelSelectorRequirement"}: "k8s.io/client-go/applyconfigurations/meta/v1", + {Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ManagedFieldsEntry"}: "k8s.io/client-go/applyconfigurations/meta/v1", + {Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ObjectMeta"}: "k8s.io/client-go/applyconfigurations/meta/v1", + {Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "OwnerReference"}: "k8s.io/client-go/applyconfigurations/meta/v1", + {Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "TypeMeta"}: "k8s.io/client-go/applyconfigurations/meta/v1", + }, + } +} + +func (args *Args) AddFlags(fs *pflag.FlagSet, inputBase string) { + fs.StringVar(&args.OutputDir, "output-dir", "", + "the base directory under which to generate results") + fs.StringVar(&args.OutputPkg, "output-pkg", args.OutputPkg, + "the Go import-path of the generated results") + fs.StringVar(&args.GoHeaderFile, "go-header-file", "", + "the path to a file containing boilerplate header text; the string \"YEAR\" will be replaced with the current 4-digit year") + fs.Var(NewExternalApplyConfigurationValue(&args.ExternalApplyConfigurations, nil), "external-applyconfigurations", + "list of comma separated external apply configurations locations in .: form."+ + "For example: k8s.io/api/apps/v1.Deployment:k8s.io/client-go/applyconfigurations/apps/v1") + fs.StringVar(&args.OpenAPISchemaFilePath, "openapi-schema", "", + "path to the openapi schema containing all the types that apply configurations will be generated for") +} + +// Validate checks the given arguments. +func (args *Args) Validate() error { + if len(args.OutputDir) == 0 { + return fmt.Errorf("--output-dir must be specified") + } + if len(args.OutputPkg) == 0 { + return fmt.Errorf("--output-pkg must be specified") + } + return nil +} diff --git a/code-generator/cmd/applyconfiguration-gen/args/externaltypes.go b/code-generator/cmd/applyconfiguration-gen/args/externaltypes.go new file mode 100644 index 000000000..fd9b60989 --- /dev/null +++ b/code-generator/cmd/applyconfiguration-gen/args/externaltypes.go @@ -0,0 +1,122 @@ +/* +Copyright 2021 The Kubernetes 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 ( + "bytes" + "encoding/csv" + "flag" + "fmt" + "strings" + + "k8s.io/gengo/v2/types" +) + +type externalApplyConfigurationValue struct { + externals *map[types.Name]string +} + +func NewExternalApplyConfigurationValue(externals *map[types.Name]string, def []string) *externalApplyConfigurationValue { + val := new(externalApplyConfigurationValue) + val.externals = externals + if def != nil { + if err := val.set(def); err != nil { + panic(err) + } + } + return val +} + +var _ flag.Value = &externalApplyConfigurationValue{} + +func (s *externalApplyConfigurationValue) set(vs []string) error { + for _, input := range vs { + typ, pkg, err := parseExternalMapping(input) + if err != nil { + return err + } + if _, ok := (*s.externals)[typ]; ok { + return fmt.Errorf("duplicate type found in --external-applyconfigurations: %v", typ) + } + (*s.externals)[typ] = pkg + } + + return nil +} + +func (s *externalApplyConfigurationValue) Set(val string) error { + vs, err := readAsCSV(val) + if err != nil { + return err + } + if err := s.set(vs); err != nil { + return err + } + + return nil +} + +func (s *externalApplyConfigurationValue) Type() string { + return "string" +} + +func (s *externalApplyConfigurationValue) String() string { + var strs []string + for k, v := range *s.externals { + strs = append(strs, fmt.Sprintf("%s.%s:%s", k.Package, k.Name, v)) + } + str, _ := writeAsCSV(strs) + return "[" + str + "]" +} + +func readAsCSV(val string) ([]string, error) { + if val == "" { + return []string{}, nil + } + stringReader := strings.NewReader(val) + csvReader := csv.NewReader(stringReader) + return csvReader.Read() +} + +func writeAsCSV(vals []string) (string, error) { + b := &bytes.Buffer{} + w := csv.NewWriter(b) + err := w.Write(vals) + if err != nil { + return "", err + } + w.Flush() + return strings.TrimSuffix(b.String(), "\n"), nil +} + +func parseExternalMapping(mapping string) (typ types.Name, pkg string, err error) { + parts := strings.Split(mapping, ":") + if len(parts) != 2 { + return types.Name{}, "", fmt.Errorf("expected string of the form .: but got %s", mapping) + } + packageTypeStr := parts[0] + pkg = parts[1] + // need to split on the *last* dot, since k8s.io (and other valid packages) have a dot in it + lastDot := strings.LastIndex(packageTypeStr, ".") + if lastDot == -1 || lastDot == len(packageTypeStr)-1 { + return types.Name{}, "", fmt.Errorf("expected package and type of the form . but got %s", packageTypeStr) + } + structPkg := packageTypeStr[:lastDot] + structType := packageTypeStr[lastDot+1:] + + return types.Name{Package: structPkg, Name: structType}, pkg, nil +} diff --git a/code-generator/cmd/applyconfiguration-gen/generators/applyconfiguration.go b/code-generator/cmd/applyconfiguration-gen/generators/applyconfiguration.go new file mode 100644 index 000000000..9b6aa7cec --- /dev/null +++ b/code-generator/cmd/applyconfiguration-gen/generators/applyconfiguration.go @@ -0,0 +1,479 @@ +/* +Copyright 2021 The Kubernetes 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" + "path" + "slices" + "strings" + + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + "k8s.io/klog/v2" + + "k8s.io/code-generator/cmd/client-gen/generators/util" + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" +) + +// applyConfigurationGenerator produces apply configurations for a given GroupVersion and type. +type applyConfigurationGenerator struct { + generator.GoGenerator + // outPkgBase is the base package, under which the "internal" and GV-specific subdirs live + outPkgBase string // must be a Go import-path + localPkg string + groupVersion clientgentypes.GroupVersion + applyConfig applyConfig + imports namer.ImportTracker + refGraph refGraph + openAPIType *string // if absent, extraction function cannot be generated +} + +var _ generator.Generator = &applyConfigurationGenerator{} + +func (g *applyConfigurationGenerator) Filter(_ *generator.Context, t *types.Type) bool { + return t == g.applyConfig.Type +} + +func (g *applyConfigurationGenerator) Namers(*generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.localPkg, g.imports), + "singularKind": namer.NewPublicNamer(0), + } +} + +func (g *applyConfigurationGenerator) Imports(*generator.Context) (imports []string) { + return g.imports.ImportLines() +} + +// TypeParams provides a struct that an apply configuration +// is generated for as well as the apply configuration details +// and types referenced by the struct. +type TypeParams struct { + Struct *types.Type + ApplyConfig applyConfig + Tags util.Tags + APIVersion string + ExtractInto *types.Type + ParserFunc *types.Type + OpenAPIType *string +} + +type memberParams struct { + TypeParams + Member types.Member + MemberType *types.Type + JSONTags JSONTags + ArgType *types.Type // only set for maps and slices + EmbeddedIn *memberParams // parent embedded member, if any +} + +func (g *applyConfigurationGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + + klog.V(5).Infof("processing type %v", t) + typeParams := TypeParams{ + Struct: t, + ApplyConfig: g.applyConfig, + Tags: genclientTags(t), + APIVersion: g.groupVersion.ToAPIVersion(), + ExtractInto: extractInto, + ParserFunc: types.Ref(path.Join(g.outPkgBase, "internal"), "Parser"), + OpenAPIType: g.openAPIType, + } + + g.generateStruct(sw, typeParams) + + if typeParams.Tags.GenerateClient { + if typeParams.Tags.NonNamespaced { + sw.Do(clientgenTypeConstructorNonNamespaced, typeParams) + } else { + sw.Do(clientgenTypeConstructorNamespaced, typeParams) + } + if typeParams.OpenAPIType != nil { + g.generateClientgenExtract(sw, typeParams, !typeParams.Tags.NoStatus) + } + } else { + if hasTypeMetaField(t) { + sw.Do(constructorWithTypeMeta, typeParams) + } else { + sw.Do(constructor, typeParams) + } + } + g.generateWithFuncs(t, typeParams, sw, nil, &[]string{}) + g.generateGetters(t, typeParams, sw, nil) + return sw.Error() +} + +func hasTypeMetaField(t *types.Type) bool { + for _, member := range t.Members { + if typeMeta.Name == member.Type.Name && member.Embedded { + return true + } + } + return false +} + +func blocklisted(t *types.Type, member types.Member) bool { + if objectMeta.Name == t.Name && member.Name == "ManagedFields" { + return true + } + if objectMeta.Name == t.Name && member.Name == "SelfLink" { + return true + } + // Hide any fields which are en route to deletion. + if strings.HasPrefix(member.Name, "ZZZ_") { + return true + } + return false +} + +func needsGetter(t *types.Type, member types.Member) bool { + // Needed when applying an ApplyConfiguration + return objectMeta.Name == t.Name && member.Name == "Name" +} + +func (g *applyConfigurationGenerator) generateGetters(t *types.Type, typeParams TypeParams, sw *generator.SnippetWriter, embed *memberParams) { + for _, member := range t.Members { + if blocklisted(t, member) { + continue + } + memberType := g.refGraph.applyConfigForType(member.Type) + if g.refGraph.isApplyConfig(member.Type) { + memberType = &types.Type{Kind: types.Pointer, Elem: memberType} + } + if jsonTags, ok := lookupJSONTags(member); ok { + memberParams := memberParams{ + TypeParams: typeParams, + Member: member, + MemberType: memberType, + JSONTags: jsonTags, + EmbeddedIn: embed, + } + if memberParams.Member.Embedded { + g.generateGetters(member.Type, typeParams, sw, &memberParams) + continue + } + + if needsGetter(t, member) { + g.generateMemberGetter(sw, memberParams) + } + } + } +} + +func (g *applyConfigurationGenerator) generateWithFuncs(t *types.Type, typeParams TypeParams, sw *generator.SnippetWriter, embed *memberParams, + generated *[]string) { + for _, member := range t.Members { + if blocklisted(t, member) { + continue + } + memberType := g.refGraph.applyConfigForType(member.Type) + if g.refGraph.isApplyConfig(member.Type) { + memberType = &types.Type{Kind: types.Pointer, Elem: memberType} + } + if jsonTags, ok := lookupJSONTags(member); ok { + if slices.Contains(*generated, member.Name) { + klog.V(5).Infof("With%s already generated on %s, skipping\n", member.Name, t.Name) + continue + } + *generated = append(*generated, member.Name) + memberParams := memberParams{ + TypeParams: typeParams, + Member: member, + MemberType: memberType, + JSONTags: jsonTags, + EmbeddedIn: embed, + } + if memberParams.Member.Embedded { + g.generateWithFuncs(member.Type, typeParams, sw, &memberParams, generated) + if !jsonTags.inline { + // non-inlined embeds are nillable and need a "ensure exists" utility function + sw.Do(ensureEmbedExists, memberParams) + } + continue + } + + // For slices where the items are generated apply configuration types, accept varargs of + // pointers of the type as "with" function arguments so the "with" function can be used like so: + // WithFoos(Foo().WithName("x"), Foo().WithName("y")) + if t := deref(member.Type); t.Kind == types.Slice && g.refGraph.isApplyConfig(t.Elem) { + memberParams.ArgType = &types.Type{Kind: types.Pointer, Elem: memberType.Elem} + g.generateMemberWithForSlice(sw, member, memberParams) + continue + } + // Note: There are no maps where the values are generated apply configurations (because + // associative lists are used instead). So if a type like this is ever introduced, the + // default "with" function generator will produce a working (but not entirely convenient "with" function) + // that would be used like so: + // WithMap(map[string]FooApplyConfiguration{*Foo().WithName("x")}) + + switch memberParams.Member.Type.Kind { + case types.Slice: + memberParams.ArgType = memberType.Elem + g.generateMemberWithForSlice(sw, member, memberParams) + case types.Map: + g.generateMemberWithForMap(sw, memberParams) + default: + g.generateMemberWith(sw, memberParams) + } + } + } +} + +func (g *applyConfigurationGenerator) generateStruct(sw *generator.SnippetWriter, typeParams TypeParams) { + sw.Do("// $.ApplyConfig.ApplyConfiguration|public$ represents a declarative configuration of the $.ApplyConfig.Type|public$ type for use\n", typeParams) + sw.Do("// with apply.\n", typeParams) + sw.Do("type $.ApplyConfig.ApplyConfiguration|public$ struct {\n", typeParams) + for _, structMember := range typeParams.Struct.Members { + if blocklisted(typeParams.Struct, structMember) { + continue + } + if structMemberTags, ok := lookupJSONTags(structMember); ok { + if !structMemberTags.inline { + structMemberTags.omitempty = true + } + params := memberParams{ + TypeParams: typeParams, + Member: structMember, + MemberType: g.refGraph.applyConfigForType(structMember.Type), + JSONTags: structMemberTags, + } + if structMember.Embedded { + if structMemberTags.inline { + sw.Do("$.MemberType|raw$ `json:\"$.JSONTags$\"`\n", params) + } else { + sw.Do("*$.MemberType|raw$ `json:\"$.JSONTags$\"`\n", params) + } + } else if isNillable(structMember.Type) { + sw.Do("$.Member.Name$ $.MemberType|raw$ `json:\"$.JSONTags$\"`\n", params) + } else { + sw.Do("$.Member.Name$ *$.MemberType|raw$ `json:\"$.JSONTags$\"`\n", params) + } + } + } + sw.Do("}\n", typeParams) +} + +func deref(t *types.Type) *types.Type { + for t.Kind == types.Pointer { + t = t.Elem + } + return t +} + +func isNillable(t *types.Type) bool { + return t.Kind == types.Slice || t.Kind == types.Map +} + +func (g *applyConfigurationGenerator) generateMemberWith(sw *generator.SnippetWriter, memberParams memberParams) { + sw.Do("// With$.Member.Name$ sets the $.Member.Name$ field in the declarative configuration to the given value\n", memberParams) + sw.Do("// and returns the receiver, so that objects can be built by chaining \"With\" function invocations.\n", memberParams) + sw.Do("// If called multiple times, the $.Member.Name$ field is set to the value of the last call.\n", memberParams) + sw.Do("func (b *$.ApplyConfig.ApplyConfiguration|public$) With$.Member.Name$(value $.MemberType|raw$) *$.ApplyConfig.ApplyConfiguration|public$ {\n", memberParams) + g.ensureEmbedExistsIfApplicable(sw, memberParams) + if g.refGraph.isApplyConfig(memberParams.Member.Type) || isNillable(memberParams.Member.Type) { + sw.Do("b$if ne .EmbeddedIn nil$.$.EmbeddedIn.MemberType.Elem.Name.Name$$end$.$.Member.Name$ = value\n", memberParams) + } else { + sw.Do("b$if ne .EmbeddedIn nil$.$.EmbeddedIn.MemberType.Elem.Name.Name$$end$.$.Member.Name$ = &value\n", memberParams) + } + sw.Do(" return b\n", memberParams) + sw.Do("}\n", memberParams) +} + +func (g *applyConfigurationGenerator) generateMemberGetter(sw *generator.SnippetWriter, memberParams memberParams) { + sw.Do("// Get$.Member.Name$ retrieves the value of the $.Member.Name$ field in the declarative configuration.\n", memberParams) + if g.refGraph.isApplyConfig(memberParams.Member.Type) || isNillable(memberParams.Member.Type) { + sw.Do("func (b *$.ApplyConfig.ApplyConfiguration|public$) Get$.Member.Name$() $.MemberType|raw$ {\n", memberParams) + } else { + sw.Do("func (b *$.ApplyConfig.ApplyConfiguration|public$) Get$.Member.Name$() *$.MemberType|raw$ {\n", memberParams) + } + g.ensureEmbedExistsIfApplicable(sw, memberParams) + sw.Do(" return b$if ne .EmbeddedIn nil$.$.EmbeddedIn.MemberType.Elem.Name.Name$$end$.$.Member.Name$\n", memberParams) + sw.Do("}\n", memberParams) +} + +func (g *applyConfigurationGenerator) generateMemberWithForSlice(sw *generator.SnippetWriter, member types.Member, memberParams memberParams) { + memberIsPointerToSlice := member.Type.Kind == types.Pointer + if memberIsPointerToSlice { + sw.Do(ensureNonEmbedSliceExists, memberParams) + } + + sw.Do("// With$.Member.Name$ adds the given value to the $.Member.Name$ field in the declarative configuration\n", memberParams) + sw.Do("// and returns the receiver, so that objects can be build by chaining \"With\" function invocations.\n", memberParams) + sw.Do("// If called multiple times, values provided by each call will be appended to the $.Member.Name$ field.\n", memberParams) + sw.Do("func (b *$.ApplyConfig.ApplyConfiguration|public$) With$.Member.Name$(values ...$.ArgType|raw$) *$.ApplyConfig.ApplyConfiguration|public$ {\n", memberParams) + g.ensureEmbedExistsIfApplicable(sw, memberParams) + + if memberIsPointerToSlice { + sw.Do("b.ensure$.MemberType.Elem|public$Exists()\n", memberParams) + } + + sw.Do(" for i := range values {\n", memberParams) + if memberParams.ArgType.Kind == types.Pointer { + sw.Do("if values[i] == nil {\n", memberParams) + sw.Do(" panic(\"nil value passed to With$.Member.Name$\")\n", memberParams) + sw.Do("}\n", memberParams) + + if memberIsPointerToSlice { + sw.Do("*b$if ne .EmbeddedIn nil$.$.EmbeddedIn.MemberType.Elem.Name.Name$$end$.$.Member.Name$ = append(*b$if ne .EmbeddedIn nil$.$.EmbeddedIn.MemberType.Elem.Name.Name$$end$.$.Member.Name$, *values[i])\n", memberParams) + } else { + sw.Do("b$if ne .EmbeddedIn nil$.$.EmbeddedIn.MemberType.Elem.Name.Name$$end$.$.Member.Name$ = append(b$if ne .EmbeddedIn nil$.$.EmbeddedIn.MemberType.Elem.Name.Name$$end$.$.Member.Name$, *values[i])\n", memberParams) + } + } else { + if memberIsPointerToSlice { + sw.Do("*b$if ne .EmbeddedIn nil$.$.EmbeddedIn.MemberType.Elem.Name.Name$$end$.$.Member.Name$ = append(*b$if ne .EmbeddedIn nil$.$.EmbeddedIn.MemberType.Elem.Name.Name$$end$.$.Member.Name$, values[i])\n", memberParams) + } else { + sw.Do("b$if ne .EmbeddedIn nil$.$.EmbeddedIn.MemberType.Elem.Name.Name$$end$.$.Member.Name$ = append(b$if ne .EmbeddedIn nil$.$.EmbeddedIn.MemberType.Elem.Name.Name$$end$.$.Member.Name$, values[i])\n", memberParams) + } + } + sw.Do(" }\n", memberParams) + sw.Do(" return b\n", memberParams) + sw.Do("}\n", memberParams) +} + +func (g *applyConfigurationGenerator) generateMemberWithForMap(sw *generator.SnippetWriter, memberParams memberParams) { + sw.Do("// With$.Member.Name$ puts the entries into the $.Member.Name$ field in the declarative configuration\n", memberParams) + sw.Do("// and returns the receiver, so that objects can be build by chaining \"With\" function invocations.\n", memberParams) + sw.Do("// If called multiple times, the entries provided by each call will be put on the $.Member.Name$ field,\n", memberParams) + sw.Do("// overwriting an existing map entries in $.Member.Name$ field with the same key.\n", memberParams) + sw.Do("func (b *$.ApplyConfig.ApplyConfiguration|public$) With$.Member.Name$(entries $.MemberType|raw$) *$.ApplyConfig.ApplyConfiguration|public$ {\n", memberParams) + g.ensureEmbedExistsIfApplicable(sw, memberParams) + sw.Do(" if b$if ne .EmbeddedIn nil$.$.EmbeddedIn.MemberType.Elem.Name.Name$$end$.$.Member.Name$ == nil && len(entries) > 0 {\n", memberParams) + sw.Do(" b$if ne .EmbeddedIn nil$.$.EmbeddedIn.MemberType.Elem.Name.Name$$end$.$.Member.Name$ = make($.MemberType|raw$, len(entries))\n", memberParams) + sw.Do(" }\n", memberParams) + sw.Do(" for k, v := range entries {\n", memberParams) + sw.Do(" b$if ne .EmbeddedIn nil$.$.EmbeddedIn.MemberType.Elem.Name.Name$$end$.$.Member.Name$[k] = v\n", memberParams) + sw.Do(" }\n", memberParams) + sw.Do(" return b\n", memberParams) + sw.Do("}\n", memberParams) +} + +func (g *applyConfigurationGenerator) ensureEmbedExistsIfApplicable(sw *generator.SnippetWriter, memberParams memberParams) { + // Embedded types that are not inlined must be nillable so they are not included in the apply configuration + // when all their fields are omitted. + if memberParams.EmbeddedIn != nil && !memberParams.EmbeddedIn.JSONTags.inline { + sw.Do("b.ensure$.MemberType.Elem|public$Exists()\n", memberParams.EmbeddedIn) + } +} + +var ensureEmbedExists = ` +func (b *$.ApplyConfig.ApplyConfiguration|public$) ensure$.MemberType.Elem|public$Exists() { + if b.$.MemberType.Elem|public$ == nil { + b.$.MemberType.Elem|public$ = &$.MemberType.Elem|raw${} + } +} +` + +var ensureNonEmbedSliceExists = ` +func (b *$.ApplyConfig.ApplyConfiguration|public$) ensure$.MemberType.Elem|public$Exists() { + if b.$.Member.Name$ == nil { + b.$.Member.Name$ = &[]$.MemberType.Elem|raw${} + } +} +` + +var clientgenTypeConstructorNamespaced = ` +// $.ApplyConfig.Type|public$ constructs a declarative configuration of the $.ApplyConfig.Type|public$ type for use with +// apply. +func $.ApplyConfig.Type|public$(name, namespace string) *$.ApplyConfig.ApplyConfiguration|public$ { + b := &$.ApplyConfig.ApplyConfiguration|public${} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("$.ApplyConfig.Type|singularKind$") + b.WithAPIVersion("$.APIVersion$") + return b +} +` + +var clientgenTypeConstructorNonNamespaced = ` +// $.ApplyConfig.Type|public$ constructs a declarative configuration of the $.ApplyConfig.Type|public$ type for use with +// apply. +func $.ApplyConfig.Type|public$(name string) *$.ApplyConfig.ApplyConfiguration|public$ { + b := &$.ApplyConfig.ApplyConfiguration|public${} + b.WithName(name) + b.WithKind("$.ApplyConfig.Type|singularKind$") + b.WithAPIVersion("$.APIVersion$") + return b +} +` + +var constructorWithTypeMeta = ` +// $.ApplyConfig.ApplyConfiguration|public$ constructs a declarative configuration of the $.ApplyConfig.Type|public$ type for use with +// apply. +func $.ApplyConfig.Type|public$() *$.ApplyConfig.ApplyConfiguration|public$ { + b := &$.ApplyConfig.ApplyConfiguration|public${} + b.WithKind("$.ApplyConfig.Type|singularKind$") + b.WithAPIVersion("$.APIVersion$") + return b +} +` + +var constructor = ` +// $.ApplyConfig.ApplyConfiguration|public$ constructs a declarative configuration of the $.ApplyConfig.Type|public$ type for use with +// apply. +func $.ApplyConfig.Type|public$() *$.ApplyConfig.ApplyConfiguration|public$ { + return &$.ApplyConfig.ApplyConfiguration|public${} +} +` + +func (g *applyConfigurationGenerator) generateClientgenExtract(sw *generator.SnippetWriter, typeParams TypeParams, includeStatus bool) { + sw.Do(` +// Extract$.ApplyConfig.Type|public$ extracts the applied configuration owned by fieldManager from +// $.Struct|private$. If no managedFields are found in $.Struct|private$ for fieldManager, a +// $.ApplyConfig.ApplyConfiguration|public$ is returned with only the Name, Namespace (if applicable), +// APIVersion and Kind populated. It is possible that no managed fields were found for because other +// field managers have taken ownership of all the fields previously owned by fieldManager, or because +// the fieldManager never owned fields any fields. +// $.Struct|private$ must be a unmodified $.Struct|public$ API object that was retrieved from the Kubernetes API. +// Extract$.ApplyConfig.Type|public$ provides a way to perform a extract/modify-in-place/apply workflow. +// Note that an extracted apply configuration will contain fewer fields than what the fieldManager previously +// applied if another fieldManager has updated or force applied any of the previously applied fields. +// Experimental! +func Extract$.ApplyConfig.Type|public$($.Struct|private$ *$.Struct|raw$, fieldManager string) (*$.ApplyConfig.ApplyConfiguration|public$, error) { + return extract$.ApplyConfig.Type|public$($.Struct|private$, fieldManager, "") +}`, typeParams) + if includeStatus { + sw.Do(` +// Extract$.ApplyConfig.Type|public$Status is the same as Extract$.ApplyConfig.Type|public$ except +// that it extracts the status subresource applied configuration. +// Experimental! +func Extract$.ApplyConfig.Type|public$Status($.Struct|private$ *$.Struct|raw$, fieldManager string) (*$.ApplyConfig.ApplyConfiguration|public$, error) { + return extract$.ApplyConfig.Type|public$($.Struct|private$, fieldManager, "status") +} +`, typeParams) + } + sw.Do(` +func extract$.ApplyConfig.Type|public$($.Struct|private$ *$.Struct|raw$, fieldManager string, subresource string) (*$.ApplyConfig.ApplyConfiguration|public$, error) { + b := &$.ApplyConfig.ApplyConfiguration|public${} + err := $.ExtractInto|raw$($.Struct|private$, $.ParserFunc|raw$().Type("$.OpenAPIType$"), fieldManager, b, subresource) + if err != nil { + return nil, err + } + b.WithName($.Struct|private$.Name) +`, typeParams) + if !typeParams.Tags.NonNamespaced { + sw.Do("b.WithNamespace($.Struct|private$.Namespace)\n", typeParams) + } + sw.Do(` + b.WithKind("$.ApplyConfig.Type|singularKind$") + b.WithAPIVersion("$.APIVersion$") + return b, nil +} +`, typeParams) +} diff --git a/code-generator/cmd/applyconfiguration-gen/generators/internal.go b/code-generator/cmd/applyconfiguration-gen/generators/internal.go new file mode 100644 index 000000000..f8d659e43 --- /dev/null +++ b/code-generator/cmd/applyconfiguration-gen/generators/internal.go @@ -0,0 +1,101 @@ +/* +Copyright 2021 The Kubernetes 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" + + "gopkg.in/yaml.v2" + + "k8s.io/kube-openapi/pkg/schemaconv" + + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" +) + +// utilGenerator generates the ForKind() utility function. +type internalGenerator struct { + generator.GoGenerator + outputPackage string + imports namer.ImportTracker + typeModels *typeModels + filtered bool +} + +var _ generator.Generator = &internalGenerator{} + +func (g *internalGenerator) Filter(*generator.Context, *types.Type) bool { + // generate file exactly once + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *internalGenerator) Namers(*generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + "singularKind": namer.NewPublicNamer(0), + } +} + +func (g *internalGenerator) Imports(*generator.Context) (imports []string) { + return g.imports.ImportLines() +} + +func (g *internalGenerator) GenerateType(c *generator.Context, _ *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + schema, err := schemaconv.ToSchema(g.typeModels.models) + if err != nil { + return err + } + schemaYAML, err := yaml.Marshal(schema) + if err != nil { + return err + } + sw.Do(schemaBlock, map[string]interface{}{ + "schemaYAML": string(schemaYAML), + "smdParser": smdParser, + "smdNewParser": smdNewParser, + "fmtSprintf": fmtSprintf, + "syncOnce": syncOnce, + "yamlObject": yamlObject, + "yamlUnmarshal": yamlUnmarshal, + }) + + return sw.Error() +} + +var schemaBlock = ` +func Parser() *{{.smdParser|raw}} { + parserOnce.Do(func() { + var err error + parser, err = {{.smdNewParser|raw}}(schemaYAML) + if err != nil { + panic({{.fmtSprintf|raw}}("Failed to parse schema: %v", err)) + } + }) + return parser +} + +var parserOnce {{.syncOnce|raw}} +var parser *{{.smdParser|raw}} +var schemaYAML = {{.yamlObject|raw}}(` + "`{{.schemaYAML}}`" + `) +` diff --git a/code-generator/cmd/applyconfiguration-gen/generators/jsontagutil.go b/code-generator/cmd/applyconfiguration-gen/generators/jsontagutil.go new file mode 100644 index 000000000..c11d05dee --- /dev/null +++ b/code-generator/cmd/applyconfiguration-gen/generators/jsontagutil.go @@ -0,0 +1,99 @@ +/* +Copyright 2021 The Kubernetes 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 ( + "reflect" + "strings" + + "k8s.io/gengo/v2/types" +) + +// TODO: This implements the same functionality as https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apimachinery/pkg/runtime/converter.go#L236 +// but is based on the highly efficient approach from https://golang.org/src/encoding/json/encode.go + +// JSONTags represents a go json field tag. +type JSONTags struct { + name string + omit bool + inline bool + omitempty bool +} + +func (t JSONTags) String() string { + var tag string + if !t.inline { + tag += t.name + } + if t.omitempty { + tag += ",omitempty" + } + if t.inline { + tag += ",inline" + } + return tag +} + +func lookupJSONTags(m types.Member) (JSONTags, bool) { + tag := reflect.StructTag(m.Tags).Get("json") + if tag == "" || tag == "-" { + return JSONTags{}, false + } + name, opts := parseTag(tag) + if name == "" { + name = m.Name + } + return JSONTags{ + name: name, + omit: false, + inline: opts.Contains("inline"), + omitempty: opts.Contains("omitempty"), + }, true +} + +type tagOptions string + +// parseTag splits a struct field's json tag into its name and +// comma-separated options. +func parseTag(tag string) (string, tagOptions) { + if idx := strings.Index(tag, ","); idx != -1 { + return tag[:idx], tagOptions(tag[idx+1:]) + } + return tag, "" +} + +// Contains reports whether a comma-separated listAlias of options +// contains a particular substr flag. substr must be surrounded by a +// string boundary or commas. +func (o tagOptions) Contains(optionName string) bool { + if len(o) == 0 { + return false + } + s := string(o) + for s != "" { + var next string + i := strings.Index(s, ",") + if i >= 0 { + s, next = s[:i], s[i+1:] + } + if s == optionName { + return true + } + s = next + } + return false +} diff --git a/code-generator/cmd/applyconfiguration-gen/generators/openapi.go b/code-generator/cmd/applyconfiguration-gen/generators/openapi.go new file mode 100644 index 000000000..674413602 --- /dev/null +++ b/code-generator/cmd/applyconfiguration-gen/generators/openapi.go @@ -0,0 +1,192 @@ +/* +Copyright 2021 The Kubernetes 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 ( + "encoding/json" + "fmt" + "os" + "strings" + + openapiv2 "github.com/google/gnostic-models/openapiv2" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/v2/types" + utilproto "k8s.io/kube-openapi/pkg/util/proto" + "k8s.io/kube-openapi/pkg/validation/spec" +) + +type typeModels struct { + models utilproto.Models + gvkToOpenAPIType map[clientgentypes.GroupVersionKind]string +} + +func newTypeModels(openAPISchemaFilePath string, pkgTypes map[string]*types.Package) (*typeModels, error) { + if len(openAPISchemaFilePath) == 0 { + return emptyModels, nil // No Extract() functions will be generated. + } + + rawOpenAPISchema, err := os.ReadFile(openAPISchemaFilePath) + if err != nil { + return nil, fmt.Errorf("failed to read openapi-schema file: %w", err) + } + + // Read in the provided openAPI schema. + openAPISchema := &spec.Swagger{} + err = json.Unmarshal(rawOpenAPISchema, openAPISchema) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal typeModels JSON: %w", err) + } + + // Build a mapping from openAPI type name to GVK. + // Find the root types needed by by client-go for apply. + gvkToOpenAPIType := map[clientgentypes.GroupVersionKind]string{} + rootDefs := map[string]spec.Schema{} + for _, p := range pkgTypes { + gv := groupVersion(p) + for _, t := range p.Types { + tags := genclientTags(t) + hasApply := tags.HasVerb("apply") || tags.HasVerb("applyStatus") + if tags.GenerateClient && hasApply { + openAPIType := friendlyName(typeName(t)) + gvk := gv.WithKind(clientgentypes.Kind(t.Name.Name)) + rootDefs[openAPIType] = openAPISchema.Definitions[openAPIType] + gvkToOpenAPIType[gvk] = openAPIType + } + } + } + + // Trim the schema down to just the types needed by client-go for apply. + requiredDefs := make(map[string]spec.Schema) + for name, def := range rootDefs { + requiredDefs[name] = def + findReferenced(&def, openAPISchema.Definitions, requiredDefs) + } + openAPISchema.Definitions = requiredDefs + + // Convert the openAPI schema to the models format and validate it. + models, err := toValidatedModels(openAPISchema) + if err != nil { + return nil, err + } + return &typeModels{models: models, gvkToOpenAPIType: gvkToOpenAPIType}, nil +} + +var emptyModels = &typeModels{ + models: &utilproto.Definitions{}, + gvkToOpenAPIType: map[clientgentypes.GroupVersionKind]string{}, +} + +func toValidatedModels(openAPISchema *spec.Swagger) (utilproto.Models, error) { + // openapi_v2.ParseDocument only accepts a []byte of the JSON or YAML file to be parsed. + // so we do an inefficient marshal back to json and then read it back in as yaml + // but get the benefit of running the models through utilproto.NewOpenAPIData to + // validate all the references between types + rawMinimalOpenAPISchema, err := json.Marshal(openAPISchema) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal openAPI as JSON: %w", err) + } + + document, err := openapiv2.ParseDocument(rawMinimalOpenAPISchema) + if err != nil { + return nil, fmt.Errorf("failed to parse OpenAPI document for file: %w", err) + } + // Construct the models and validate all references are valid. + models, err := utilproto.NewOpenAPIData(document) + if err != nil { + return nil, fmt.Errorf("failed to create OpenAPI models for file: %w", err) + } + return models, nil +} + +// findReferenced recursively finds all schemas referenced from the given def. +// toValidatedModels makes sure no references get missed. +func findReferenced(def *spec.Schema, allSchemas, referencedOut map[string]spec.Schema) { + // follow $ref, if any + refPtr := def.Ref.GetPointer() + if refPtr != nil && !refPtr.IsEmpty() { + name := refPtr.String() + if !strings.HasPrefix(name, "/definitions/") { + return + } + name = strings.TrimPrefix(name, "/definitions/") + schema, ok := allSchemas[name] + if !ok { + panic(fmt.Sprintf("allSchemas schema is missing referenced type: %s", name)) + } + if _, ok := referencedOut[name]; !ok { + referencedOut[name] = schema + findReferenced(&schema, allSchemas, referencedOut) + } + } + + // follow any nested schemas + if def.Items != nil { + if def.Items.Schema != nil { + findReferenced(def.Items.Schema, allSchemas, referencedOut) + } + for _, item := range def.Items.Schemas { + findReferenced(&item, allSchemas, referencedOut) + } + } + if def.AllOf != nil { + for _, s := range def.AllOf { + findReferenced(&s, allSchemas, referencedOut) + } + } + if def.AnyOf != nil { + for _, s := range def.AnyOf { + findReferenced(&s, allSchemas, referencedOut) + } + } + if def.OneOf != nil { + for _, s := range def.OneOf { + findReferenced(&s, allSchemas, referencedOut) + } + } + if def.Not != nil { + findReferenced(def.Not, allSchemas, referencedOut) + } + if def.Properties != nil { + for _, prop := range def.Properties { + findReferenced(&prop, allSchemas, referencedOut) + } + } + if def.AdditionalProperties != nil && def.AdditionalProperties.Schema != nil { + findReferenced(def.AdditionalProperties.Schema, allSchemas, referencedOut) + } + if def.PatternProperties != nil { + for _, s := range def.PatternProperties { + findReferenced(&s, allSchemas, referencedOut) + } + } + if def.Dependencies != nil { + for _, d := range def.Dependencies { + if d.Schema != nil { + findReferenced(d.Schema, allSchemas, referencedOut) + } + } + } + if def.AdditionalItems != nil && def.AdditionalItems.Schema != nil { + findReferenced(def.AdditionalItems.Schema, allSchemas, referencedOut) + } + if def.Definitions != nil { + for _, s := range def.Definitions { + findReferenced(&s, allSchemas, referencedOut) + } + } +} diff --git a/code-generator/cmd/applyconfiguration-gen/generators/refgraph.go b/code-generator/cmd/applyconfiguration-gen/generators/refgraph.go new file mode 100644 index 000000000..8b4675529 --- /dev/null +++ b/code-generator/cmd/applyconfiguration-gen/generators/refgraph.go @@ -0,0 +1,175 @@ +/* +Copyright 2021 The Kubernetes 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 ( + "k8s.io/gengo/v2/types" + + "k8s.io/code-generator/cmd/client-gen/generators/util" +) + +// refGraph maps existing types to the package the corresponding applyConfig types will be generated in +// so that references between apply configurations can be correctly generated. +type refGraph map[types.Name]string + +// refGraphForReachableTypes returns a refGraph that contains all reachable types from +// the root clientgen types of the provided packages. +func refGraphForReachableTypes(universe types.Universe, pkgTypes map[string]*types.Package, initialTypes map[types.Name]string) refGraph { + var refs refGraph = initialTypes + + // Include only types that are reachable from the root clientgen types. + // We don't want to generate apply configurations for types that are not reachable from a root + // clientgen type. + reachableTypes := map[types.Name]*types.Type{} + for _, p := range pkgTypes { + for _, t := range p.Types { + tags := genclientTags(t) + hasApply := tags.HasVerb("apply") || tags.HasVerb("applyStatus") + if tags.GenerateClient && hasApply { + findReachableTypes(t, reachableTypes) + } + // If any apply extensions have custom inputs, add them. + for _, extension := range tags.Extensions { + if extension.HasVerb("apply") { + if len(extension.InputTypeOverride) > 0 { + inputType := *t + if name, pkg := extension.Input(); len(pkg) > 0 { + inputType = *(universe.Type(types.Name{Package: pkg, Name: name})) + } else { + inputType.Name.Name = extension.InputTypeOverride + } + findReachableTypes(&inputType, reachableTypes) + } + } + } + } + } + for pkg, p := range pkgTypes { + for _, t := range p.Types { + if _, ok := reachableTypes[t.Name]; !ok { + continue + } + if requiresApplyConfiguration(t) { + refs[t.Name] = pkg + } + } + } + + return refs +} + +// applyConfigForType find the type used in the generate apply configurations for a field. +// This may either be an existing type or one of the other generated applyConfig types. +func (t refGraph) applyConfigForType(field *types.Type) *types.Type { + switch field.Kind { + case types.Struct: + if pkg, ok := t[field.Name]; ok { // TODO(jpbetz): Refs to types defined in a separate system (e.g. TypeMeta if generating a 3rd party controller) end up referencing the go struct, not the apply configuration type + return types.Ref(pkg, field.Name.Name+ApplyConfigurationTypeSuffix) + } + return field + case types.Map: + if _, ok := t[field.Elem.Name]; ok { + return &types.Type{ + Kind: types.Map, + Elem: t.applyConfigForType(field.Elem), + Key: t.applyConfigForType(field.Key), + } + } + return field + case types.Slice: + if _, ok := t[field.Elem.Name]; ok { + return &types.Type{ + Kind: types.Slice, + Elem: t.applyConfigForType(field.Elem), + } + } + return field + case types.Pointer: + return t.applyConfigForType(field.Elem) + default: + return field + } +} + +func (t refGraph) isApplyConfig(field *types.Type) bool { + switch field.Kind { + case types.Struct: + _, ok := t[field.Name] + return ok + case types.Pointer: + return t.isApplyConfig(field.Elem) + } + return false +} + +// genclientTags returns the genclient Tags for the given type. +func genclientTags(t *types.Type) util.Tags { + return util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) +} + +// findReachableTypes finds all types transitively reachable from a given root type, including +// the root type itself. +func findReachableTypes(t *types.Type, referencedTypes map[types.Name]*types.Type) { + if _, ok := referencedTypes[t.Name]; ok { + return + } + referencedTypes[t.Name] = t + + if t.Elem != nil { + findReachableTypes(t.Elem, referencedTypes) + } + if t.Underlying != nil { + findReachableTypes(t.Underlying, referencedTypes) + } + if t.Key != nil { + findReachableTypes(t.Key, referencedTypes) + } + for _, m := range t.Members { + findReachableTypes(m.Type, referencedTypes) + } +} + +// excludeTypes contains well known types that we do not generate apply configurations for. +// Hard coding because we only have two, very specific types that serve a special purpose +// in the type system here. +var excludeTypes = map[types.Name]struct{}{ + rawExtension.Name: {}, + unknown.Name: {}, + // DO NOT ADD TO THIS LIST. If we need to exclude other types, we should consider allowing the + // go type declarations to be annotated as excluded from this generator. +} + +// requiresApplyConfiguration returns true if a type applyConfig should be generated for the given type. +// types applyConfig are only generated for struct types that contain fields with json tags. +func requiresApplyConfiguration(t *types.Type) bool { + for t.Kind == types.Alias { + t = t.Underlying + } + if t.Kind != types.Struct { + return false + } + if _, ok := excludeTypes[t.Name]; ok { + return false + } + var hasJSONTaggedMembers bool + for _, member := range t.Members { + if _, ok := lookupJSONTags(member); ok { + hasJSONTaggedMembers = true + } + } + return hasJSONTaggedMembers +} diff --git a/code-generator/cmd/applyconfiguration-gen/generators/targets.go b/code-generator/cmd/applyconfiguration-gen/generators/targets.go new file mode 100644 index 000000000..b033d22d8 --- /dev/null +++ b/code-generator/cmd/applyconfiguration-gen/generators/targets.go @@ -0,0 +1,314 @@ +/* +Copyright 2021 The Kubernetes 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 ( + "fmt" + "path" + "path/filepath" + "sort" + "strings" + + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + "k8s.io/klog/v2" + + "k8s.io/code-generator/cmd/applyconfiguration-gen/args" + "k8s.io/code-generator/cmd/client-gen/generators/util" + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" +) + +const ( + // ApplyConfigurationTypeSuffix is the suffix of generated apply configuration types. + ApplyConfigurationTypeSuffix = "ApplyConfiguration" +) + +// NameSystems returns the name system used by the generators in this package. +func NameSystems() namer.NameSystems { + return namer.NameSystems{ + "public": namer.NewPublicNamer(0), + "private": namer.NewPrivateNamer(0), + "raw": namer.NewRawNamer("", nil), + } +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +// GetTargets makes the client target definition. +func GetTargets(context *generator.Context, args *args.Args) []generator.Target { + boilerplate, err := gengo.GoBoilerplate(args.GoHeaderFile, "", gengo.StdGeneratedBy) + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + pkgTypes := packageTypesForInputs(context, args.OutputPkg) + initialTypes := args.ExternalApplyConfigurations + refs := refGraphForReachableTypes(context.Universe, pkgTypes, initialTypes) + typeModels, err := newTypeModels(args.OpenAPISchemaFilePath, pkgTypes) + if err != nil { + klog.Fatalf("Failed build type models from typeModels %s: %v", args.OpenAPISchemaFilePath, err) + } + + groupVersions := make(map[string]clientgentypes.GroupVersions) + groupGoNames := make(map[string]string) + applyConfigsForGroupVersion := make(map[clientgentypes.GroupVersion][]applyConfig) + + var targetList []generator.Target + for pkg, p := range pkgTypes { + gv := groupVersion(p) + + var toGenerate []applyConfig + for _, t := range p.Types { + // If we don't have an ObjectMeta field, we lack the information required to make the Apply or ApplyStatus call + // to the kube-apiserver, so we don't need to generate the type at all + clientTags := genclientTags(t) + if clientTags.GenerateClient && !hasObjectMetaField(t) { + klog.V(5).Infof("skipping type %v because does not have ObjectMeta", t) + continue + } + gvk := gv.WithKind(clientgentypes.Kind(t.Name.Name)) + openAPIName := typeModels.gvkToOpenAPIType[gvk] + + if typePkg, ok := refs[t.Name]; ok { + toGenerate = append(toGenerate, applyConfig{ + Type: t, + ApplyConfiguration: types.Ref(typePkg, t.Name.Name+ApplyConfigurationTypeSuffix), + OpenAPIName: openAPIName, + }) + } + } + if len(toGenerate) == 0 { + continue // Don't generate empty packages + } + sort.Sort(applyConfigSort(toGenerate)) + + // Apparently we allow the groupName to be overridden in a way that it + // no longer maps to a Go package by name. So we have to figure out + // the offset of this particular output package (pkg) from the base + // output package (args.OutputPkg). + pkgSubdir := strings.TrimPrefix(pkg, args.OutputPkg+"/") + + // generate the apply configurations + targetList = append(targetList, + targetForApplyConfigurationsPackage( + args.OutputDir, args.OutputPkg, pkgSubdir, + boilerplate, gv, toGenerate, refs, typeModels)) + + // group all the generated apply configurations by gv so ForKind() can be generated + groupPackageName := gv.Group.NonEmpty() + groupVersionsEntry, ok := groupVersions[groupPackageName] + if !ok { + groupVersionsEntry = clientgentypes.GroupVersions{ + PackageName: groupPackageName, + Group: gv.Group, + } + } + groupVersionsEntry.Versions = append(groupVersionsEntry.Versions, clientgentypes.PackageVersion{ + Version: gv.Version, + Package: path.Clean(p.Path), + }) + + groupGoNames[groupPackageName] = goName(gv, p) + applyConfigsForGroupVersion[gv] = toGenerate + groupVersions[groupPackageName] = groupVersionsEntry + } + + // generate ForKind() utility function + targetList = append(targetList, + targetForUtils(args.OutputDir, args.OutputPkg, + boilerplate, groupVersions, applyConfigsForGroupVersion, groupGoNames, typeModels)) + // generate internal embedded schema, required for generated Extract functions + targetList = append(targetList, + targetForInternal(args.OutputDir, args.OutputPkg, + boilerplate, typeModels)) + + return targetList +} + +func friendlyName(name string) string { + nameParts := strings.Split(name, "/") + // Reverse first part. e.g., io.k8s... instead of k8s.io... + if len(nameParts) > 0 && strings.Contains(nameParts[0], ".") { + parts := strings.Split(nameParts[0], ".") + for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 { + parts[i], parts[j] = parts[j], parts[i] + } + nameParts[0] = strings.Join(parts, ".") + } + return strings.Join(nameParts, ".") +} + +func typeName(t *types.Type) string { + typePackage := t.Name.Package + return fmt.Sprintf("%s.%s", typePackage, t.Name.Name) +} + +func targetForApplyConfigurationsPackage(outputDirBase, outputPkgBase, pkgSubdir string, boilerplate []byte, gv clientgentypes.GroupVersion, typesToGenerate []applyConfig, refs refGraph, models *typeModels) generator.Target { + outputDir := filepath.Join(outputDirBase, pkgSubdir) + outputPkg := path.Join(outputPkgBase, pkgSubdir) + + return &generator.SimpleTarget{ + PkgName: gv.Version.PackageName(), + PkgPath: outputPkg, + PkgDir: outputDir, + HeaderComment: boilerplate, + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + for _, toGenerate := range typesToGenerate { + var openAPIType *string + gvk := gv.WithKind(clientgentypes.Kind(toGenerate.Type.Name.Name)) + if v, ok := models.gvkToOpenAPIType[gvk]; ok { + openAPIType = &v + } + + generators = append(generators, &applyConfigurationGenerator{ + GoGenerator: generator.GoGenerator{ + OutputFilename: strings.ToLower(toGenerate.Type.Name.Name) + ".go", + }, + outPkgBase: outputPkgBase, + localPkg: outputPkg, + groupVersion: gv, + applyConfig: toGenerate, + imports: generator.NewImportTrackerForPackage(outputPkg), + refGraph: refs, + openAPIType: openAPIType, + }) + } + return generators + }, + } +} + +func targetForUtils(outputDirBase, outputPkgBase string, boilerplate []byte, groupVersions map[string]clientgentypes.GroupVersions, + applyConfigsForGroupVersion map[clientgentypes.GroupVersion][]applyConfig, groupGoNames map[string]string, models *typeModels) generator.Target { + return &generator.SimpleTarget{ + PkgName: path.Base(outputPkgBase), + PkgPath: outputPkgBase, + PkgDir: outputDirBase, + HeaderComment: boilerplate, + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = append(generators, &utilGenerator{ + GoGenerator: generator.GoGenerator{ + OutputFilename: "utils.go", + }, + outputPackage: outputPkgBase, + imports: generator.NewImportTrackerForPackage(outputPkgBase), + groupVersions: groupVersions, + typesForGroupVersion: applyConfigsForGroupVersion, + groupGoNames: groupGoNames, + typeModels: models, + }) + return generators + }, + } +} + +func targetForInternal(outputDirBase, outputPkgBase string, boilerplate []byte, models *typeModels) generator.Target { + outputDir := filepath.Join(outputDirBase, "internal") + outputPkg := path.Join(outputPkgBase, "internal") + return &generator.SimpleTarget{ + PkgName: path.Base(outputPkg), + PkgPath: outputPkg, + PkgDir: outputDir, + HeaderComment: boilerplate, + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = append(generators, &internalGenerator{ + GoGenerator: generator.GoGenerator{ + OutputFilename: "internal.go", + }, + outputPackage: outputPkgBase, + imports: generator.NewImportTrackerForPackage(outputPkg), + typeModels: models, + }) + return generators + }, + } +} + +func goName(gv clientgentypes.GroupVersion, p *types.Package) string { + goName := namer.IC(strings.Split(gv.Group.NonEmpty(), ".")[0]) + if override := gengo.ExtractCommentTags("+", p.Comments)["groupGoName"]; override != nil { + goName = namer.IC(override[0]) + } + return goName +} + +func packageTypesForInputs(context *generator.Context, outPkgBase string) map[string]*types.Package { + pkgTypes := map[string]*types.Package{} + for _, inputDir := range context.Inputs { + p := context.Universe.Package(inputDir) + internal := isInternalPackage(p) + if internal { + klog.Warningf("Skipping internal package: %s", p.Path) + continue + } + // This is how the client generator finds the package we are creating. It uses the API package name, not the group name. + // This matches the approach of the client-gen, so the two generator can work together. + // For example, if openshift/api/cloudnetwork/v1 contains an apigroup cloud.network.openshift.io, the client-gen + // builds a package called cloudnetwork/v1 to contain it. This change makes the applyconfiguration-gen use the same. + _, gvPackageString := util.ParsePathGroupVersion(p.Path) + pkg := path.Join(outPkgBase, strings.ToLower(gvPackageString)) + pkgTypes[pkg] = p + } + return pkgTypes +} + +func groupVersion(p *types.Package) (gv clientgentypes.GroupVersion) { + parts := strings.Split(p.Path, "/") + gv.Group = clientgentypes.Group(parts[len(parts)-2]) + gv.Version = clientgentypes.Version(parts[len(parts)-1]) + + // 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 := gengo.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil { + gv.Group = clientgentypes.Group(override[0]) + } + return gv +} + +// isInternalPackage returns true if the package is an internal package +func isInternalPackage(p *types.Package) bool { + for _, t := range p.Types { + for _, member := range t.Members { + if member.Name == "ObjectMeta" { + return isInternal(member) + } + } + } + return false +} + +// isInternal returns true if the tags for a member do not contain a json tag +func isInternal(m types.Member) bool { + _, ok := lookupJSONTags(m) + return !ok +} + +func hasObjectMetaField(t *types.Type) bool { + for _, member := range t.Members { + if objectMeta.Name == member.Type.Name && member.Embedded { + return true + } + } + return false +} diff --git a/code-generator/cmd/applyconfiguration-gen/generators/types.go b/code-generator/cmd/applyconfiguration-gen/generators/types.go new file mode 100644 index 000000000..95e6bb345 --- /dev/null +++ b/code-generator/cmd/applyconfiguration-gen/generators/types.go @@ -0,0 +1,37 @@ +/* +Copyright 2021 The Kubernetes 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 "k8s.io/gengo/v2/types" + +var ( + fmtSprintf = types.Ref("fmt", "Sprintf") + syncOnce = types.Ref("sync", "Once") + applyConfiguration = types.Ref("k8s.io/apimachinery/pkg/runtime", "ApplyConfiguration") + groupVersionKind = types.Ref("k8s.io/apimachinery/pkg/runtime/schema", "GroupVersionKind") + typeMeta = types.Ref("k8s.io/apimachinery/pkg/apis/meta/v1", "TypeMeta") + objectMeta = types.Ref("k8s.io/apimachinery/pkg/apis/meta/v1", "ObjectMeta") + rawExtension = types.Ref("k8s.io/apimachinery/pkg/runtime", "RawExtension") + unknown = types.Ref("k8s.io/apimachinery/pkg/runtime", "Unknown") + extractInto = types.Ref("k8s.io/apimachinery/pkg/util/managedfields", "ExtractInto") + runtimeScheme = types.Ref("k8s.io/apimachinery/pkg/runtime", "Scheme") + smdNewParser = types.Ref("sigs.k8s.io/structured-merge-diff/v4/typed", "NewParser") + smdParser = types.Ref("sigs.k8s.io/structured-merge-diff/v4/typed", "Parser") + testingTypeConverter = types.Ref("k8s.io/client-go/testing", "TypeConverter") + yamlObject = types.Ref("sigs.k8s.io/structured-merge-diff/v4/typed", "YAMLObject") + yamlUnmarshal = types.Ref("gopkg.in/yaml.v2", "Unmarshal") +) diff --git a/code-generator/cmd/applyconfiguration-gen/generators/util.go b/code-generator/cmd/applyconfiguration-gen/generators/util.go new file mode 100644 index 000000000..136d9c495 --- /dev/null +++ b/code-generator/cmd/applyconfiguration-gen/generators/util.go @@ -0,0 +1,176 @@ +/* +Copyright 2021 The Kubernetes 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" + "path" + "sort" + "strings" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" +) + +// utilGenerator generates the ForKind() utility function. +type utilGenerator struct { + generator.GoGenerator + outputPackage string + imports namer.ImportTracker + groupVersions map[string]clientgentypes.GroupVersions + groupGoNames map[string]string + typesForGroupVersion map[clientgentypes.GroupVersion][]applyConfig + filtered bool + typeModels *typeModels +} + +var _ generator.Generator = &utilGenerator{} + +func (g *utilGenerator) Filter(*generator.Context, *types.Type) bool { + // generate file exactly once + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *utilGenerator) Namers(*generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + "singularKind": namer.NewPublicNamer(0), + } +} + +func (g *utilGenerator) Imports(*generator.Context) (imports []string) { + return g.imports.ImportLines() +} + +type group struct { + GroupGoName string + Name string + Versions []*version +} + +type groupSort []group + +func (g groupSort) Len() int { return len(g) } +func (g groupSort) Less(i, j int) bool { + return strings.ToLower(g[i].Name) < strings.ToLower(g[j].Name) +} +func (g groupSort) Swap(i, j int) { g[i], g[j] = g[j], g[i] } + +type version struct { + Name string + GoName string + Resources []applyConfig +} + +type versionSort []*version + +func (v versionSort) Len() int { return len(v) } +func (v versionSort) Less(i, j int) bool { + return strings.ToLower(v[i].Name) < strings.ToLower(v[j].Name) +} +func (v versionSort) Swap(i, j int) { v[i], v[j] = v[j], v[i] } + +type applyConfig struct { + Type *types.Type + ApplyConfiguration *types.Type + OpenAPIName string +} + +type applyConfigSort []applyConfig + +func (v applyConfigSort) Len() int { return len(v) } +func (v applyConfigSort) Less(i, j int) bool { + return strings.ToLower(v[i].Type.Name.Name) < strings.ToLower(v[j].Type.Name.Name) +} +func (v applyConfigSort) Swap(i, j int) { v[i], v[j] = v[j], v[i] } + +func (g *utilGenerator) GenerateType(c *generator.Context, _ *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + var groups []group + schemeGVs := make(map[*version]*types.Type) + + for groupPackageName, groupVersions := range g.groupVersions { + group := group{ + GroupGoName: g.groupGoNames[groupPackageName], + Name: groupVersions.Group.NonEmpty(), + Versions: []*version{}, + } + for _, v := range groupVersions.Versions { + gv := clientgentypes.GroupVersion{Group: groupVersions.Group, Version: v.Version} + version := &version{ + Name: v.Version.NonEmpty(), + GoName: namer.IC(v.Version.NonEmpty()), + Resources: g.typesForGroupVersion[gv], + } + schemeGVs[version] = c.Universe.Variable(types.Name{ + Package: g.typesForGroupVersion[gv][0].Type.Name.Package, + Name: "SchemeGroupVersion", + }) + group.Versions = append(group.Versions, version) + } + sort.Sort(versionSort(group.Versions)) + groups = append(groups, group) + } + sort.Sort(groupSort(groups)) + + m := map[string]interface{}{ + "applyConfiguration": applyConfiguration, + "groups": groups, + "internalParser": types.Ref(path.Join(g.outputPackage, "internal"), "Parser"), + "runtimeScheme": runtimeScheme, + "schemeGVs": schemeGVs, + "schemaGroupVersionKind": groupVersionKind, + "testingTypeConverter": testingTypeConverter, + } + sw.Do(forKindFunc, m) + sw.Do(typeConverter, m) + + return sw.Error() +} + +var typeConverter = ` +func NewTypeConverter(scheme *{{.runtimeScheme|raw}}) *{{.testingTypeConverter|raw}} { + return &{{.testingTypeConverter|raw}}{Scheme: scheme, TypeResolver: {{.internalParser|raw}}()} +} +` + +var forKindFunc = ` +// ForKind returns an apply configuration type for the given GroupVersionKind, or nil if no +// apply configuration type exists for the given GroupVersionKind. +func ForKind(kind {{.schemaGroupVersionKind|raw}}) interface{} { + switch kind { + {{range $group := .groups -}}{{$GroupGoName := .GroupGoName -}} + {{range $version := .Versions -}} + // Group={{$group.Name}}, Version={{.Name}} + {{range .Resources -}} + case {{index $.schemeGVs $version|raw}}.WithKind("{{.Type|singularKind}}"): + return &{{.ApplyConfiguration|raw}}{} + {{end}} + {{end}} + {{end -}} + } + return nil +} +` diff --git a/code-generator/cmd/applyconfiguration-gen/main.go b/code-generator/cmd/applyconfiguration-gen/main.go new file mode 100644 index 000000000..f6b03f887 --- /dev/null +++ b/code-generator/cmd/applyconfiguration-gen/main.go @@ -0,0 +1,60 @@ +/* +Copyright 2021 The Kubernetes 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. +*/ + +// applyconfiguration-gen is a tool for auto-generating apply builder functions. +package main + +import ( + "flag" + + "github.com/spf13/pflag" + "k8s.io/code-generator/cmd/applyconfiguration-gen/args" + "k8s.io/code-generator/cmd/applyconfiguration-gen/generators" + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/klog/v2" +) + +func main() { + klog.InitFlags(nil) + args := args.New() + args.AddFlags(pflag.CommandLine, "k8s.io/kubernetes/pkg/apis") // TODO: move this input path out of applyconfiguration-gen + if err := flag.Set("logtostderr", "true"); err != nil { + klog.Fatalf("Error: %v", err) + } + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + if err := args.Validate(); err != nil { + klog.Fatalf("Error: %v", err) + } + + myTargets := func(context *generator.Context) []generator.Target { + return generators.GetTargets(context, args) + } + + // Run it. + if err := gengo.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + myTargets, + gengo.StdBuildTag, + pflag.Args(), + ); err != nil { + klog.Fatalf("Error: %v", err) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/code-generator/cmd/client-gen/OWNERS b/code-generator/cmd/client-gen/OWNERS new file mode 100644 index 000000000..967eb2a7b --- /dev/null +++ b/code-generator/cmd/client-gen/OWNERS @@ -0,0 +1,11 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +approvers: + - wojtek-t + - caesarxuchao +reviewers: + - wojtek-t + - caesarxuchao + - jpbetz +emeritus_approvers: + - lavalamp diff --git a/code-generator/cmd/client-gen/README.md b/code-generator/cmd/client-gen/README.md new file mode 100644 index 000000000..b8206127f --- /dev/null +++ b/code-generator/cmd/client-gen/README.md @@ -0,0 +1,2 @@ +See [generating-clientset.md](https://git.k8s.io/community/contributors/devel/sig-api-machinery/generating-clientset.md) + diff --git a/code-generator/cmd/client-gen/args/args.go b/code-generator/cmd/client-gen/args/args.go new file mode 100644 index 000000000..e0914e69d --- /dev/null +++ b/code-generator/cmd/client-gen/args/args.go @@ -0,0 +1,142 @@ +/* +Copyright 2015 The Kubernetes 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/code-generator/cmd/client-gen/types" +) + +type Args struct { + // The directory for the generated results. + OutputDir string + + // The Go import-path of the generated results. + OutputPkg string + + // The boilerplate header for Go files. + GoHeaderFile string + + // A sorted list of group versions to generate. For each of them the package path is found + // in GroupVersionToInputPath. + Groups []types.GroupVersions + + // Overrides for which types should be included in the client. + IncludedTypesOverrides map[types.GroupVersion][]string + + // ClientsetName is the name of the clientset to be generated. It's + // populated from command-line arguments. + ClientsetName string + // ClientsetAPIPath is the default API HTTP path for generated clients. + ClientsetAPIPath string + // ClientsetOnly determines if we should generate the clients for groups and + // types along with the clientset. It's populated from command-line + // arguments. + ClientsetOnly bool + // FakeClient determines if client-gen generates the fake clients. + FakeClient bool + // PluralExceptions specify list of exceptions used when pluralizing certain types. + // For example 'Endpoints:Endpoints', otherwise the pluralizer will generate 'Endpointes'. + PluralExceptions []string + + // ApplyConfigurationPackage is the package of apply builders generated by + // applyconfiguration-gen. + // If non-empty, Apply functions are generated for each type and reference the apply builders. + // If empty (""), Apply functions are not generated. + ApplyConfigurationPackage string +} + +func New() *Args { + return &Args{ + ClientsetName: "internalclientset", + ClientsetAPIPath: "/apis", + ClientsetOnly: false, + FakeClient: true, + ApplyConfigurationPackage: "", + } +} + +func (args *Args) AddFlags(fs *pflag.FlagSet, inputBase string) { + gvsBuilder := NewGroupVersionsBuilder(&args.Groups) + fs.StringVar(&args.OutputDir, "output-dir", "", + "the base directory under which to generate results") + fs.StringVar(&args.OutputPkg, "output-pkg", args.OutputPkg, + "the Go import-path of the generated results") + fs.StringVar(&args.GoHeaderFile, "go-header-file", "", + "the path to a file containing boilerplate header text; the string \"YEAR\" will be replaced with the current 4-digit year") + fs.Var(NewGVPackagesValue(gvsBuilder, nil), "input", + "group/versions that client-gen will generate clients for. At most one version per group is allowed. Specified in the format \"group1/version1,group2/version2...\".") + fs.Var(NewGVTypesValue(&args.IncludedTypesOverrides, []string{}), "included-types-overrides", + "list of group/version/type for which client should be generated. By default, client is generated for all types which have genclient in types.go. This overrides that. For each groupVersion in this list, only the types mentioned here will be included. The default check of genclient will be used for other group versions.") + fs.Var(NewInputBasePathValue(gvsBuilder, inputBase), "input-base", + "base path to look for the api group.") + fs.StringVarP(&args.ClientsetName, "clientset-name", "n", args.ClientsetName, + "the name of the generated clientset package.") + fs.StringVarP(&args.ClientsetAPIPath, "clientset-api-path", "", args.ClientsetAPIPath, + "the value of default API HTTP path, starting with / and without trailing /.") + fs.BoolVar(&args.ClientsetOnly, "clientset-only", args.ClientsetOnly, + "when set, client-gen only generates the clientset shell, without generating the individual typed clients") + fs.BoolVar(&args.FakeClient, "fake-clientset", args.FakeClient, + "when set, client-gen will generate the fake clientset that can be used in tests") + fs.StringSliceVar(&args.PluralExceptions, "plural-exceptions", args.PluralExceptions, + "list of comma separated plural exception definitions in Type:PluralizedType form") + fs.StringVar(&args.ApplyConfigurationPackage, "apply-configuration-package", args.ApplyConfigurationPackage, + "optional package of apply configurations, generated by applyconfiguration-gen, that are required to generate Apply functions for each type in the clientset. By default Apply functions are not generated.") + + // support old flags + fs.SetNormalizeFunc(mapFlagName("clientset-path", "output-pkg", fs.GetNormalizeFunc())) +} + +func (args *Args) Validate() error { + if len(args.OutputDir) == 0 { + return fmt.Errorf("--output-dir must be specified") + } + if len(args.OutputPkg) == 0 { + return fmt.Errorf("--output-pkg must be specified") + } + if len(args.ClientsetName) == 0 { + return fmt.Errorf("--clientset-name must be specified") + } + if len(args.ClientsetAPIPath) == 0 { + return fmt.Errorf("--clientset-api-path cannot be empty") + } + + return nil +} + +// GroupVersionPackages returns a map from GroupVersion to the package with the types.go. +func (args *Args) GroupVersionPackages() map[types.GroupVersion]string { + res := map[types.GroupVersion]string{} + for _, pkg := range args.Groups { + for _, v := range pkg.Versions { + res[types.GroupVersion{Group: pkg.Group, Version: v.Version}] = v.Package + } + } + return res +} + +func mapFlagName(from, to string, old func(fs *pflag.FlagSet, name string) pflag.NormalizedName) func(fs *pflag.FlagSet, name string) pflag.NormalizedName { + return func(fs *pflag.FlagSet, name string) pflag.NormalizedName { + if name == from { + name = to + } + return old(fs, name) + } +} diff --git a/code-generator/cmd/client-gen/args/gvpackages.go b/code-generator/cmd/client-gen/args/gvpackages.go new file mode 100644 index 000000000..f5e7f4063 --- /dev/null +++ b/code-generator/cmd/client-gen/args/gvpackages.go @@ -0,0 +1,175 @@ +/* +Copyright 2017 The Kubernetes 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 ( + "bytes" + "encoding/csv" + "flag" + "path" + "sort" + "strings" + + "k8s.io/code-generator/cmd/client-gen/generators/util" + "k8s.io/code-generator/cmd/client-gen/types" +) + +type inputBasePathValue struct { + builder *groupVersionsBuilder +} + +var _ flag.Value = &inputBasePathValue{} + +func NewInputBasePathValue(builder *groupVersionsBuilder, def string) *inputBasePathValue { + v := &inputBasePathValue{ + builder: builder, + } + v.Set(def) + return v +} + +func (s *inputBasePathValue) Set(val string) error { + s.builder.importBasePath = val + return s.builder.update() +} + +func (s *inputBasePathValue) Type() string { + return "string" +} + +func (s *inputBasePathValue) String() string { + return s.builder.importBasePath +} + +type gvPackagesValue struct { + builder *groupVersionsBuilder + groups []string + changed bool +} + +func NewGVPackagesValue(builder *groupVersionsBuilder, def []string) *gvPackagesValue { + gvp := new(gvPackagesValue) + gvp.builder = builder + if def != nil { + if err := gvp.set(def); err != nil { + panic(err) + } + } + return gvp +} + +var _ flag.Value = &gvPackagesValue{} + +func (s *gvPackagesValue) set(vs []string) error { + if s.changed { + s.groups = append(s.groups, vs...) + } else { + s.groups = append([]string(nil), vs...) + } + + s.builder.groups = s.groups + return s.builder.update() +} + +func (s *gvPackagesValue) Set(val string) error { + vs, err := readAsCSV(val) + if err != nil { + return err + } + if err := s.set(vs); err != nil { + return err + } + s.changed = true + return nil +} + +func (s *gvPackagesValue) Type() string { + return "stringSlice" +} + +func (s *gvPackagesValue) String() string { + str, _ := writeAsCSV(s.groups) + return "[" + str + "]" +} + +type groupVersionsBuilder struct { + value *[]types.GroupVersions + groups []string + importBasePath string +} + +func NewGroupVersionsBuilder(groups *[]types.GroupVersions) *groupVersionsBuilder { + return &groupVersionsBuilder{ + value: groups, + } +} + +func (p *groupVersionsBuilder) update() error { + var seenGroups = make(map[types.Group]*types.GroupVersions) + for _, v := range p.groups { + pth, gvString := util.ParsePathGroupVersion(v) + gv, err := types.ToGroupVersion(gvString) + if err != nil { + return err + } + + versionPkg := types.PackageVersion{Package: path.Join(p.importBasePath, pth, gv.Group.NonEmpty(), gv.Version.String()), Version: gv.Version} + if group, ok := seenGroups[gv.Group]; ok { + vers := group.Versions + vers = append(vers, versionPkg) + seenGroups[gv.Group].Versions = vers + } else { + seenGroups[gv.Group] = &types.GroupVersions{ + PackageName: gv.Group.NonEmpty(), + Group: gv.Group, + Versions: []types.PackageVersion{versionPkg}, + } + } + } + + var groupNames []string + for groupName := range seenGroups { + groupNames = append(groupNames, groupName.String()) + } + sort.Strings(groupNames) + *p.value = []types.GroupVersions{} + for _, groupName := range groupNames { + *p.value = append(*p.value, *seenGroups[types.Group(groupName)]) + } + + return nil +} + +func readAsCSV(val string) ([]string, error) { + if val == "" { + return []string{}, nil + } + stringReader := strings.NewReader(val) + csvReader := csv.NewReader(stringReader) + return csvReader.Read() +} + +func writeAsCSV(vals []string) (string, error) { + b := &bytes.Buffer{} + w := csv.NewWriter(b) + err := w.Write(vals) + if err != nil { + return "", err + } + w.Flush() + return strings.TrimSuffix(b.String(), "\n"), nil +} diff --git a/code-generator/cmd/client-gen/args/gvpackages_test.go b/code-generator/cmd/client-gen/args/gvpackages_test.go new file mode 100644 index 000000000..3f7eb8902 --- /dev/null +++ b/code-generator/cmd/client-gen/args/gvpackages_test.go @@ -0,0 +1,116 @@ +/* +Copyright 2017 The Kubernetes 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" + "reflect" + "strings" + "testing" + + "github.com/spf13/pflag" + + "k8s.io/code-generator/cmd/client-gen/types" +) + +func TestGVPackageFlag(t *testing.T) { + tests := []struct { + args []string + def []string + importBasePath string + expected map[types.GroupVersion]string + expectedGroups []types.GroupVersions + parseError string + }{ + { + args: []string{}, + expected: map[types.GroupVersion]string{}, + expectedGroups: []types.GroupVersions{}, + }, + { + args: []string{"foo/bar/v1", "foo/bar/v2", "foo/bar/", "foo/v1"}, + expectedGroups: []types.GroupVersions{ + {PackageName: "bar", Group: types.Group("bar"), Versions: []types.PackageVersion{ + {Version: "v1", Package: "foo/bar/v1"}, + {Version: "v2", Package: "foo/bar/v2"}, + {Version: "", Package: "foo/bar"}, + }}, + {PackageName: "foo", Group: types.Group("foo"), Versions: []types.PackageVersion{ + {Version: "v1", Package: "foo/v1"}, + }}, + }, + }, + { + args: []string{"foo/bar/v1", "foo/bar/v2", "foo/bar/", "foo/v1"}, + def: []string{"foo/bar/v1alpha1", "foo/v1"}, + expectedGroups: []types.GroupVersions{ + {PackageName: "bar", Group: types.Group("bar"), Versions: []types.PackageVersion{ + {Version: "v1", Package: "foo/bar/v1"}, + {Version: "v2", Package: "foo/bar/v2"}, + {Version: "", Package: "foo/bar"}, + }}, + {PackageName: "foo", Group: types.Group("foo"), Versions: []types.PackageVersion{ + {Version: "v1", Package: "foo/v1"}, + }}, + }, + }, + { + args: []string{"api/v1", "api"}, + expectedGroups: []types.GroupVersions{ + {PackageName: "api", Group: types.Group("api"), Versions: []types.PackageVersion{ + {Version: "v1", Package: "api/v1"}, + {Version: "", Package: "api"}, + }}, + }, + }, + { + args: []string{"foo/v1"}, + importBasePath: "k8s.io/api", + expectedGroups: []types.GroupVersions{ + {PackageName: "foo", Group: types.Group("foo"), Versions: []types.PackageVersion{ + {Version: "v1", Package: "k8s.io/api/foo/v1"}, + }}, + }, + }, + } + for i, test := range tests { + fs := pflag.NewFlagSet("testGVPackage", pflag.ContinueOnError) + groups := []types.GroupVersions{} + builder := NewGroupVersionsBuilder(&groups) + fs.Var(NewGVPackagesValue(builder, test.def), "input", "usage") + fs.Var(NewInputBasePathValue(builder, test.importBasePath), "input-base-path", "usage") + + args := []string{} + for _, a := range test.args { + args = append(args, fmt.Sprintf("--input=%s", a)) + } + + err := fs.Parse(args) + if test.parseError != "" { + if err == nil { + t.Errorf("%d: expected error %q, got nil", i, test.parseError) + } else if !strings.Contains(err.Error(), test.parseError) { + t.Errorf("%d: expected error %q, got %q", i, test.parseError, err) + } + } else if err != nil { + t.Errorf("%d: expected nil error, got %v", i, err) + } + if !reflect.DeepEqual(groups, test.expectedGroups) { + t.Errorf("%d: expected groups %+v, got groups %+v", i, test.expectedGroups, groups) + } + } +} diff --git a/code-generator/cmd/client-gen/args/gvtype.go b/code-generator/cmd/client-gen/args/gvtype.go new file mode 100644 index 000000000..e4e3ccb53 --- /dev/null +++ b/code-generator/cmd/client-gen/args/gvtype.go @@ -0,0 +1,110 @@ +/* +Copyright 2017 The Kubernetes 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 ( + "flag" + "fmt" + "strings" + + "k8s.io/code-generator/cmd/client-gen/types" +) + +type gvTypeValue struct { + gvToTypes *map[types.GroupVersion][]string + changed bool +} + +func NewGVTypesValue(gvToTypes *map[types.GroupVersion][]string, def []string) *gvTypeValue { + gvt := new(gvTypeValue) + gvt.gvToTypes = gvToTypes + if def != nil { + if err := gvt.set(def); err != nil { + panic(err) + } + } + return gvt +} + +var _ flag.Value = &gvTypeValue{} + +func (s *gvTypeValue) set(vs []string) error { + if !s.changed { + *s.gvToTypes = map[types.GroupVersion][]string{} + } + + for _, input := range vs { + gvString, typeStr, err := parseGroupVersionType(input) + if err != nil { + return err + } + gv, err := types.ToGroupVersion(gvString) + if err != nil { + return err + } + types, ok := (*s.gvToTypes)[gv] + if !ok { + types = []string{} + } + types = append(types, typeStr) + (*s.gvToTypes)[gv] = types + } + + return nil +} + +func (s *gvTypeValue) Set(val string) error { + vs, err := readAsCSV(val) + if err != nil { + return err + } + if err := s.set(vs); err != nil { + return err + } + s.changed = true + return nil +} + +func (s *gvTypeValue) Type() string { + return "stringSlice" +} + +func (s *gvTypeValue) String() string { + strs := make([]string, 0, len(*s.gvToTypes)) + for gv, ts := range *s.gvToTypes { + for _, t := range ts { + strs = append(strs, gv.Group.String()+"/"+gv.Version.String()+"/"+t) + } + } + str, _ := writeAsCSV(strs) + return "[" + str + "]" +} + +func parseGroupVersionType(gvtString string) (gvString string, typeStr string, err error) { + invalidFormatErr := fmt.Errorf("invalid value: %s, should be of the form group/version/type", gvtString) + subs := strings.Split(gvtString, "/") + length := len(subs) + switch length { + case 2: + // gvtString of the form group/type, e.g. api/Service,extensions/ReplicaSet + return subs[0] + "/", subs[1], nil + case 3: + return strings.Join(subs[:length-1], "/"), subs[length-1], nil + default: + return "", "", invalidFormatErr + } +} diff --git a/code-generator/cmd/client-gen/generators/client_generator.go b/code-generator/cmd/client-gen/generators/client_generator.go new file mode 100644 index 000000000..1fc21c224 --- /dev/null +++ b/code-generator/cmd/client-gen/generators/client_generator.go @@ -0,0 +1,436 @@ +/* +Copyright 2015 The Kubernetes 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 has the generators for the client-gen utility. +package generators + +import ( + "fmt" + "path" + "path/filepath" + "strings" + + "k8s.io/code-generator/cmd/client-gen/args" + "k8s.io/code-generator/cmd/client-gen/generators/fake" + "k8s.io/code-generator/cmd/client-gen/generators/scheme" + "k8s.io/code-generator/cmd/client-gen/generators/util" + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + codegennamer "k8s.io/code-generator/pkg/namer" + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + + "k8s.io/klog/v2" +) + +// NameSystems returns the name system used by the generators in this package. +func NameSystems(pluralExceptions map[string]string) namer.NameSystems { + lowercaseNamer := namer.NewAllLowercasePluralNamer(pluralExceptions) + + publicNamer := &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.NewPublicNamer(0), + } + privateNamer := &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.NewPrivateNamer(0), + } + 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(pluralExceptions), + } + privatePluralNamer := &ExceptionNamer{ + Exceptions: map[string]string{ + // 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" + // these exceptions are used to deconflict the generated code + "k8s.io/apis/events/v1beta1.Event": "eventResources", + "k8s.io/kubernetes/pkg/apis/events.Event": "eventResources", + }, + KeyFunc: func(t *types.Type) string { + return t.Name.Package + "." + t.Name.Name + }, + Delegate: namer.NewPrivatePluralNamer(pluralExceptions), + } + + return namer.NameSystems{ + "singularKind": namer.NewPublicNamer(0), + "public": publicNamer, + "private": privateNamer, + "raw": namer.NewRawNamer("", nil), + "publicPlural": publicPluralNamer, + "privatePlural": privatePluralNamer, + "allLowercasePlural": lowercaseNamer, + "resource": codegennamer.NewTagOverrideNamer("resourceName", lowercaseNamer), + } +} + +// 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) +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +func targetForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, clientsetDir, clientsetPkg string, groupPkgName string, groupGoName string, apiPath string, inputPkg string, applyBuilderPkg string, boilerplate []byte) generator.Target { + subdir := []string{"typed", strings.ToLower(groupPkgName), strings.ToLower(gv.Version.NonEmpty())} + gvDir := filepath.Join(clientsetDir, filepath.Join(subdir...)) + gvPkg := path.Join(clientsetPkg, path.Join(subdir...)) + + return &generator.SimpleTarget{ + PkgName: strings.ToLower(gv.Version.NonEmpty()), + PkgPath: gvPkg, + PkgDir: gvDir, + HeaderComment: boilerplate, + PkgDocComment: []byte("// This package has the automatically generated typed clients.\n"), + // GeneratorsFunc returns a list of generators. Each generator makes a + // single file. + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = []generator.Generator{ + // Always generate a "doc.go" file. + generator.GoGenerator{OutputFilename: "doc.go"}, + } + // Since we want a file per type that we generate a client for, we + // have to provide a function for this. + for _, t := range typeList { + generators = append(generators, &genClientForType{ + GoGenerator: generator.GoGenerator{ + OutputFilename: strings.ToLower(c.Namers["private"].Name(t)) + ".go", + }, + outputPackage: gvPkg, + inputPackage: inputPkg, + clientsetPackage: clientsetPkg, + applyConfigurationPackage: applyBuilderPkg, + group: gv.Group.NonEmpty(), + version: gv.Version.String(), + groupGoName: groupGoName, + typeToMatch: t, + imports: generator.NewImportTrackerForPackage(gvPkg), + }) + } + + generators = append(generators, &genGroup{ + GoGenerator: generator.GoGenerator{ + OutputFilename: groupPkgName + "_client.go", + }, + outputPackage: gvPkg, + inputPackage: inputPkg, + clientsetPackage: clientsetPkg, + group: gv.Group.NonEmpty(), + version: gv.Version.String(), + groupGoName: groupGoName, + apiPath: apiPath, + types: typeList, + imports: generator.NewImportTrackerForPackage(gvPkg), + }) + + expansionFileName := "generated_expansion.go" + generators = append(generators, &genExpansion{ + groupPackagePath: gvDir, + GoGenerator: generator.GoGenerator{ + OutputFilename: expansionFileName, + }, + types: typeList, + }) + + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + return util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)).GenerateClient + }, + } +} + +func targetForClientset(args *args.Args, clientsetDir, clientsetPkg string, groupGoNames map[clientgentypes.GroupVersion]string, boilerplate []byte) generator.Target { + return &generator.SimpleTarget{ + PkgName: args.ClientsetName, + PkgPath: clientsetPkg, + PkgDir: clientsetDir, + HeaderComment: boilerplate, + // GeneratorsFunc returns a list of generators. Each generator generates a + // single file. + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = []generator.Generator{ + &genClientset{ + GoGenerator: generator.GoGenerator{ + OutputFilename: "clientset.go", + }, + groups: args.Groups, + groupGoNames: groupGoNames, + clientsetPackage: clientsetPkg, + imports: generator.NewImportTrackerForPackage(clientsetPkg), + }, + } + return generators + }, + } +} + +func targetForScheme(args *args.Args, clientsetDir, clientsetPkg string, groupGoNames map[clientgentypes.GroupVersion]string, boilerplate []byte) generator.Target { + schemeDir := filepath.Join(clientsetDir, "scheme") + schemePkg := path.Join(clientsetPkg, "scheme") + + // create runtime.Registry for internal client because it has to know about group versions + internalClient := false +NextGroup: + for _, group := range args.Groups { + for _, v := range group.Versions { + if v.String() == "" { + internalClient = true + break NextGroup + } + } + } + + return &generator.SimpleTarget{ + PkgName: "scheme", + PkgPath: schemePkg, + PkgDir: schemeDir, + HeaderComment: boilerplate, + PkgDocComment: []byte("// This package contains the scheme of the automatically generated clientset.\n"), + // GeneratorsFunc returns a list of generators. Each generator generates a + // single file. + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = []generator.Generator{ + // Always generate a "doc.go" file. + generator.GoGenerator{OutputFilename: "doc.go"}, + + &scheme.GenScheme{ + GoGenerator: generator.GoGenerator{ + OutputFilename: "register.go", + }, + InputPackages: args.GroupVersionPackages(), + OutputPkg: schemePkg, + OutputPath: schemeDir, + Groups: args.Groups, + GroupGoNames: groupGoNames, + ImportTracker: generator.NewImportTrackerForPackage(schemePkg), + CreateRegistry: internalClient, + }, + } + return generators + }, + } +} + +// applyGroupOverrides applies group name overrides to each package, if applicable. If there is a +// comment of the form "// +groupName=somegroup" or "// +groupName=somegroup.foo.bar.io", use the +// first field (somegroup) as the name of the group in Go code, e.g. as the func name in a clientset. +// +// If the first field of the groupName is not unique within the clientset, use "// +groupName=unique +func applyGroupOverrides(universe types.Universe, args *args.Args) { + // Create a map from "old GV" to "new GV" so we know what changes we need to make. + changes := make(map[clientgentypes.GroupVersion]clientgentypes.GroupVersion) + for gv, inputDir := range args.GroupVersionPackages() { + p := universe.Package(inputDir) + if override := gengo.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil { + newGV := clientgentypes.GroupVersion{ + Group: clientgentypes.Group(override[0]), + Version: gv.Version, + } + changes[gv] = newGV + } + } + + // Modify args.Groups based on the groupName overrides. + newGroups := make([]clientgentypes.GroupVersions, 0, len(args.Groups)) + for _, gvs := range args.Groups { + gv := clientgentypes.GroupVersion{ + Group: gvs.Group, + Version: gvs.Versions[0].Version, // we only need a version, and the first will do + } + if newGV, ok := changes[gv]; ok { + // There's an override, so use it. + newGVS := clientgentypes.GroupVersions{ + PackageName: gvs.PackageName, + Group: newGV.Group, + Versions: gvs.Versions, + } + newGroups = append(newGroups, newGVS) + } else { + // No override. + newGroups = append(newGroups, gvs) + } + } + args.Groups = newGroups +} + +// Because we try to assemble inputs from an input-base and a set of +// group-version arguments, sometimes that comes in as a filesystem path. This +// function rewrites them all as their canonical Go import-paths. +// +// TODO: Change this tool to just take inputs as Go "patterns" like every other +// gengo tool, then extract GVs from those. +func sanitizePackagePaths(context *generator.Context, args *args.Args) error { + for i := range args.Groups { + pkg := &args.Groups[i] + for j := range pkg.Versions { + ver := &pkg.Versions[j] + input := ver.Package + p := context.Universe[input] + if p == nil || p.Name == "" { + pkgs, err := context.FindPackages(input) + if err != nil { + return fmt.Errorf("can't find input package %q: %w", input, err) + } + p = context.Universe[pkgs[0]] + if p == nil { + return fmt.Errorf("can't find input package %q in universe", input) + } + ver.Package = p.Path + } + } + } + return nil +} + +// GetTargets makes the client target definition. +func GetTargets(context *generator.Context, args *args.Args) []generator.Target { + boilerplate, err := gengo.GoBoilerplate(args.GoHeaderFile, "", gengo.StdGeneratedBy) + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + includedTypesOverrides := args.IncludedTypesOverrides + + if err := sanitizePackagePaths(context, args); err != nil { + klog.Fatalf("cannot sanitize inputs: %v", err) + } + applyGroupOverrides(context.Universe, args) + + gvToTypes := map[clientgentypes.GroupVersion][]*types.Type{} + groupGoNames := make(map[clientgentypes.GroupVersion]string) + for gv, inputDir := range args.GroupVersionPackages() { + p := context.Universe.Package(inputDir) + + // If there's a comment of the form "// +groupGoName=SomeUniqueShortName", use that as + // the Go group identifier in CamelCase. It defaults + groupGoNames[gv] = namer.IC(strings.Split(gv.Group.NonEmpty(), ".")[0]) + if override := gengo.ExtractCommentTags("+", p.Comments)["groupGoName"]; override != nil { + groupGoNames[gv] = namer.IC(override[0]) + } + + for n, t := range p.Types { + // filter out types which are not included in user specified overrides. + typesOverride, ok := includedTypesOverrides[gv] + if ok { + found := false + for _, typeStr := range typesOverride { + if typeStr == n { + found = true + break + } + } + if !found { + continue + } + } else { + // User has not specified any override for this group version. + // filter out types which don't have genclient. + if tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)); !tags.GenerateClient { + continue + } + } + if _, found := gvToTypes[gv]; !found { + gvToTypes[gv] = []*types.Type{} + } + gvToTypes[gv] = append(gvToTypes[gv], t) + } + } + + clientsetDir := filepath.Join(args.OutputDir, args.ClientsetName) + clientsetPkg := path.Join(args.OutputPkg, args.ClientsetName) + + var targetList []generator.Target + + targetList = append(targetList, + targetForClientset(args, clientsetDir, clientsetPkg, groupGoNames, boilerplate)) + targetList = append(targetList, + targetForScheme(args, clientsetDir, clientsetPkg, groupGoNames, boilerplate)) + if args.FakeClient { + targetList = append(targetList, + fake.TargetForClientset(args, clientsetDir, clientsetPkg, args.ApplyConfigurationPackage, groupGoNames, boilerplate)) + } + + // If --clientset-only=true, we don't regenerate the individual typed clients. + if args.ClientsetOnly { + return []generator.Target(targetList) + } + + orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)} + gvPackages := args.GroupVersionPackages() + for _, group := range args.Groups { + for _, version := range group.Versions { + gv := clientgentypes.GroupVersion{Group: group.Group, Version: version.Version} + types := gvToTypes[gv] + inputPath := gvPackages[gv] + targetList = append(targetList, + targetForGroup( + gv, orderer.OrderTypes(types), clientsetDir, clientsetPkg, + group.PackageName, groupGoNames[gv], args.ClientsetAPIPath, + inputPath, args.ApplyConfigurationPackage, boilerplate)) + if args.FakeClient { + targetList = append(targetList, + fake.TargetForGroup(gv, orderer.OrderTypes(types), clientsetDir, clientsetPkg, group.PackageName, groupGoNames[gv], inputPath, args.ApplyConfigurationPackage, boilerplate)) + } + } + } + + return targetList +} diff --git a/code-generator/cmd/client-gen/generators/fake/fake_client_generator.go b/code-generator/cmd/client-gen/generators/fake/fake_client_generator.go new file mode 100644 index 000000000..699c7b5f3 --- /dev/null +++ b/code-generator/cmd/client-gen/generators/fake/fake_client_generator.go @@ -0,0 +1,133 @@ +/* +Copyright 2015 The Kubernetes 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 fake + +import ( + "path" + "path/filepath" + "strings" + + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/types" + + "k8s.io/code-generator/cmd/client-gen/args" + scheme "k8s.io/code-generator/cmd/client-gen/generators/scheme" + "k8s.io/code-generator/cmd/client-gen/generators/util" + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" +) + +func TargetForGroup(gv clientgentypes.GroupVersion, typeList []*types.Type, clientsetDir, clientsetPkg string, groupPkgName string, groupGoName string, inputPkg string, applyBuilderPackage string, boilerplate []byte) generator.Target { + // TODO: should make this a function, called by here and in client-generator.go + subdir := []string{"typed", strings.ToLower(groupPkgName), strings.ToLower(gv.Version.NonEmpty())} + outputDir := filepath.Join(clientsetDir, filepath.Join(subdir...), "fake") + outputPkg := path.Join(clientsetPkg, path.Join(subdir...), "fake") + realClientPkg := path.Join(clientsetPkg, path.Join(subdir...)) + + return &generator.SimpleTarget{ + PkgName: "fake", + PkgPath: outputPkg, + PkgDir: outputDir, + HeaderComment: boilerplate, + PkgDocComment: []byte("// Package fake has the automatically generated clients.\n"), + // GeneratorsFunc returns a list of generators. Each generator makes a + // single file. + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = []generator.Generator{ + // Always generate a "doc.go" file. + generator.GoGenerator{OutputFilename: "doc.go"}, + } + // Since we want a file per type that we generate a client for, we + // have to provide a function for this. + for _, t := range typeList { + generators = append(generators, &genFakeForType{ + GoGenerator: generator.GoGenerator{ + OutputFilename: "fake_" + strings.ToLower(c.Namers["private"].Name(t)) + ".go", + }, + outputPackage: outputPkg, + inputPackage: inputPkg, + group: gv.Group.NonEmpty(), + version: gv.Version.String(), + groupGoName: groupGoName, + typeToMatch: t, + imports: generator.NewImportTrackerForPackage(outputPkg), + applyConfigurationPackage: applyBuilderPackage, + }) + } + + generators = append(generators, &genFakeForGroup{ + GoGenerator: generator.GoGenerator{ + OutputFilename: "fake_" + groupPkgName + "_client.go", + }, + outputPackage: outputPkg, + realClientPackage: realClientPkg, + group: gv.Group.NonEmpty(), + version: gv.Version.String(), + groupGoName: groupGoName, + types: typeList, + imports: generator.NewImportTrackerForPackage(outputPkg), + }) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + return util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)).GenerateClient + }, + } +} + +func TargetForClientset(args *args.Args, clientsetDir, clientsetPkg string, applyConfigurationPkg string, groupGoNames map[clientgentypes.GroupVersion]string, boilerplate []byte) generator.Target { + return &generator.SimpleTarget{ + // TODO: we'll generate fake clientset for different release in the future. + // Package name and path are hard coded for now. + PkgName: "fake", + PkgPath: path.Join(clientsetPkg, "fake"), + PkgDir: filepath.Join(clientsetDir, "fake"), + HeaderComment: boilerplate, + PkgDocComment: []byte("// This package has the automatically generated fake clientset.\n"), + // GeneratorsFunc returns a list of generators. Each generator generates a + // single file. + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = []generator.Generator{ + // Always generate a "doc.go" file. + generator.GoGenerator{OutputFilename: "doc.go"}, + + &genClientset{ + GoGenerator: generator.GoGenerator{ + OutputFilename: "clientset_generated.go", + }, + groups: args.Groups, + groupGoNames: groupGoNames, + fakeClientsetPackage: clientsetPkg, + imports: generator.NewImportTrackerForPackage(clientsetPkg), + realClientsetPackage: clientsetPkg, + applyConfigurationPackage: applyConfigurationPkg, + }, + &scheme.GenScheme{ + GoGenerator: generator.GoGenerator{ + OutputFilename: "register.go", + }, + InputPackages: args.GroupVersionPackages(), + OutputPkg: clientsetPkg, + Groups: args.Groups, + GroupGoNames: groupGoNames, + ImportTracker: generator.NewImportTrackerForPackage(clientsetPkg), + PrivateScheme: true, + }, + } + return generators + }, + } +} diff --git a/code-generator/cmd/client-gen/generators/fake/generator_fake_for_clientset.go b/code-generator/cmd/client-gen/generators/fake/generator_fake_for_clientset.go new file mode 100644 index 000000000..ffb02ebba --- /dev/null +++ b/code-generator/cmd/client-gen/generators/fake/generator_fake_for_clientset.go @@ -0,0 +1,218 @@ +/* +Copyright 2016 The Kubernetes 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 fake + +import ( + "fmt" + "io" + "path" + "strings" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" +) + +// genClientset generates a package for a clientset. +type genClientset struct { + generator.GoGenerator + groups []clientgentypes.GroupVersions + groupGoNames map[clientgentypes.GroupVersion]string + fakeClientsetPackage string // must be a Go import-path + imports namer.ImportTracker + clientsetGenerated bool + // the import path of the generated real clientset. + realClientsetPackage string // must be a Go import-path + applyConfigurationPackage string +} + +var _ generator.Generator = &genClientset{} + +func (g *genClientset) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.fakeClientsetPackage, g.imports), + } +} + +// We only want to call GenerateType() once. +func (g *genClientset) Filter(c *generator.Context, t *types.Type) bool { + ret := !g.clientsetGenerated + g.clientsetGenerated = true + return ret +} + +func (g *genClientset) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + for _, group := range g.groups { + for _, version := range group.Versions { + groupClientPackage := path.Join(g.fakeClientsetPackage, "typed", strings.ToLower(group.PackageName), strings.ToLower(version.NonEmpty())) + fakeGroupClientPackage := path.Join(groupClientPackage, "fake") + + groupAlias := strings.ToLower(g.groupGoNames[clientgentypes.GroupVersion{Group: group.Group, Version: version.Version}]) + imports = append(imports, fmt.Sprintf("%s%s \"%s\"", groupAlias, strings.ToLower(version.NonEmpty()), groupClientPackage)) + imports = append(imports, fmt.Sprintf("fake%s%s \"%s\"", groupAlias, strings.ToLower(version.NonEmpty()), fakeGroupClientPackage)) + } + } + // the package that has the clientset Interface + imports = append(imports, fmt.Sprintf("clientset \"%s\"", g.realClientsetPackage)) + // imports for the code in commonTemplate + imports = append(imports, + "k8s.io/client-go/testing", + "k8s.io/client-go/discovery", + "fakediscovery \"k8s.io/client-go/discovery/fake\"", + "k8s.io/apimachinery/pkg/runtime", + "k8s.io/apimachinery/pkg/watch", + ) + + return +} + +func (g *genClientset) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + generateApply := len(g.applyConfigurationPackage) > 0 + + // TODO: We actually don't need any type information to generate the clientset, + // perhaps we can adapt the go2ild framework to this kind of usage. + sw := generator.NewSnippetWriter(w, c, "$", "$") + + allGroups := clientgentypes.ToGroupVersionInfo(g.groups, g.groupGoNames) + + sw.Do(common, nil) + + if generateApply { + sw.Do(managedFieldsClientset, map[string]any{ + "newTypeConverter": types.Ref(g.applyConfigurationPackage, "NewTypeConverter"), + }) + } + + sw.Do(checkImpl, nil) + + for _, group := range allGroups { + m := map[string]interface{}{ + "group": group.Group, + "version": group.Version, + "PackageAlias": group.PackageAlias, + "GroupGoName": group.GroupGoName, + "Version": namer.IC(group.Version.String()), + } + + sw.Do(clientsetInterfaceImplTemplate, m) + } + + return sw.Error() +} + +// This part of code is version-independent, unchanging. + +var managedFieldsClientset = ` +// NewClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewClientset(objects ...runtime.Object) *Clientset { + o := testing.NewFieldManagedObjectTracker( + scheme, + codecs.UniversalDecoder(), + $.newTypeConverter|raw$(scheme), + ) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} +` + +var common = ` +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any field management, validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +// +// DEPRECATED: NewClientset replaces this with support for field management, which significantly improves +// server side apply testing. NewClientset is only available when apply configurations are generated (e.g. +// via --with-applyconfig). +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery + tracker testing.ObjectTracker +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +func (c *Clientset) Tracker() testing.ObjectTracker { + return c.tracker +} +` + +var checkImpl = ` +var ( + _ clientset.Interface = &Clientset{} + _ testing.FakeClient = &Clientset{} +) +` + +var clientsetInterfaceImplTemplate = ` +// $.GroupGoName$$.Version$ retrieves the $.GroupGoName$$.Version$Client +func (c *Clientset) $.GroupGoName$$.Version$() $.PackageAlias$.$.GroupGoName$$.Version$Interface { + return &fake$.PackageAlias$.Fake$.GroupGoName$$.Version${Fake: &c.Fake} +} +` diff --git a/code-generator/cmd/client-gen/generators/fake/generator_fake_for_group.go b/code-generator/cmd/client-gen/generators/fake/generator_fake_for_group.go new file mode 100644 index 000000000..d9c9b8bac --- /dev/null +++ b/code-generator/cmd/client-gen/generators/fake/generator_fake_for_group.go @@ -0,0 +1,130 @@ +/* +Copyright 2015 The Kubernetes 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 fake + +import ( + "fmt" + "io" + "path" + "strings" + + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + + "k8s.io/code-generator/cmd/client-gen/generators/util" +) + +// genFakeForGroup produces a file for a group client, e.g. ExtensionsClient for the extension group. +type genFakeForGroup struct { + generator.GoGenerator + outputPackage string // must be a Go import-path + realClientPackage string // must be a Go import-path + group string + version string + groupGoName string + // types in this group + types []*types.Type + imports namer.ImportTracker + // If the genGroup has been called. This generator should only execute once. + called bool +} + +var _ generator.Generator = &genFakeForGroup{} + +// We only want to call GenerateType() once per group. +func (g *genFakeForGroup) Filter(c *generator.Context, t *types.Type) bool { + if !g.called { + g.called = true + return true + } + return false +} + +func (g *genFakeForGroup) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *genFakeForGroup) Imports(c *generator.Context) (imports []string) { + imports = g.imports.ImportLines() + if len(g.types) != 0 { + imports = append(imports, fmt.Sprintf("%s \"%s\"", strings.ToLower(path.Base(g.realClientPackage)), g.realClientPackage)) + } + return imports +} + +func (g *genFakeForGroup) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + + m := map[string]interface{}{ + "GroupGoName": g.groupGoName, + "Version": namer.IC(g.version), + "Fake": c.Universe.Type(types.Name{Package: "k8s.io/client-go/testing", Name: "Fake"}), + "RESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}), + "RESTClient": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "RESTClient"}), + } + + sw.Do(groupClientTemplate, m) + for _, t := range g.types { + tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if err != nil { + return err + } + wrapper := map[string]interface{}{ + "type": t, + "GroupGoName": g.groupGoName, + "Version": namer.IC(g.version), + "realClientPackage": strings.ToLower(path.Base(g.realClientPackage)), + } + if tags.NonNamespaced { + sw.Do(getterImplNonNamespaced, wrapper) + continue + } + sw.Do(getterImplNamespaced, wrapper) + } + sw.Do(getRESTClient, m) + return sw.Error() +} + +var groupClientTemplate = ` +type Fake$.GroupGoName$$.Version$ struct { + *$.Fake|raw$ +} +` + +var getterImplNamespaced = ` +func (c *Fake$.GroupGoName$$.Version$) $.type|publicPlural$(namespace string) $.realClientPackage$.$.type|public$Interface { + return &Fake$.type|publicPlural${c, namespace} +} +` + +var getterImplNonNamespaced = ` +func (c *Fake$.GroupGoName$$.Version$) $.type|publicPlural$() $.realClientPackage$.$.type|public$Interface { + return &Fake$.type|publicPlural${c} +} +` + +var getRESTClient = ` +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *Fake$.GroupGoName$$.Version$) RESTClient() $.RESTClientInterface|raw$ { + var ret *$.RESTClient|raw$ + return ret +} +` diff --git a/code-generator/cmd/client-gen/generators/fake/generator_fake_for_type.go b/code-generator/cmd/client-gen/generators/fake/generator_fake_for_type.go new file mode 100644 index 000000000..0e071af92 --- /dev/null +++ b/code-generator/cmd/client-gen/generators/fake/generator_fake_for_type.go @@ -0,0 +1,587 @@ +/* +Copyright 2015 The Kubernetes 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 fake + +import ( + "io" + "path" + "strings" + + "golang.org/x/text/cases" + "golang.org/x/text/language" + + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + + "k8s.io/code-generator/cmd/client-gen/generators/util" +) + +// genFakeForType produces a file for each top-level type. +type genFakeForType struct { + generator.GoGenerator + outputPackage string // Must be a Go import-path + group string + version string + groupGoName string + inputPackage string + typeToMatch *types.Type + imports namer.ImportTracker + applyConfigurationPackage string +} + +var _ generator.Generator = &genFakeForType{} + +var titler = cases.Title(language.Und) + +// Filter ignores all but one type because we're making a single file per type. +func (g *genFakeForType) Filter(c *generator.Context, t *types.Type) bool { return t == g.typeToMatch } + +func (g *genFakeForType) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *genFakeForType) Imports(c *generator.Context) (imports []string) { + return g.imports.ImportLines() +} + +// Ideally, we'd like genStatus to return true if there is a subresource path +// registered for "status" in the API server, but we do not have that +// information, so genStatus returns true if the type has a status field. +func genStatus(t *types.Type) bool { + // Default to true if we have a Status member + hasStatus := false + for _, m := range t.Members { + if m.Name == "Status" { + hasStatus = true + break + } + } + + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return hasStatus && !tags.NoStatus +} + +// hasObjectMeta returns true if the type has a ObjectMeta field. +func hasObjectMeta(t *types.Type) bool { + for _, m := range t.Members { + if m.Embedded && m.Name == "ObjectMeta" { + return true + } + } + return false +} + +// GenerateType makes the body of a file implementing the individual typed client for type t. +func (g *genFakeForType) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + pkg := path.Base(t.Name.Package) + tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if err != nil { + return err + } + + const pkgClientGoTesting = "k8s.io/client-go/testing" + m := map[string]interface{}{ + "type": t, + "inputType": t, + "resultType": t, + "subresourcePath": "", + "package": pkg, + "Package": namer.IC(pkg), + "namespaced": !tags.NonNamespaced, + "Group": namer.IC(g.group), + "GroupGoName": g.groupGoName, + "Version": namer.IC(g.version), + "version": g.version, + "SchemeGroupVersion": c.Universe.Type(types.Name{Package: t.Name.Package, Name: "SchemeGroupVersion"}), + "CreateOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "CreateOptions"}), + "DeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}), + "GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}), + "ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}), + "PatchOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "PatchOptions"}), + "ApplyOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ApplyOptions"}), + "UpdateOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "UpdateOptions"}), + "Everything": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/labels", Name: "Everything"}), + "PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}), + "ApplyPatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "ApplyPatchType"}), + "watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"}), + "jsonMarshal": c.Universe.Type(types.Name{Package: "encoding/json", Name: "Marshal"}), + "fmtErrorf": c.Universe.Type(types.Name{Package: "fmt", Name: "Errorf"}), + "contextContext": c.Universe.Type(types.Name{Package: "context", Name: "Context"}), + + "NewRootListActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootListActionWithOptions"}), + "NewListActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewListActionWithOptions"}), + "NewRootGetActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootGetActionWithOptions"}), + "NewGetActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewGetActionWithOptions"}), + "NewRootDeleteActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootDeleteActionWithOptions"}), + "NewDeleteActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewDeleteActionWithOptions"}), + "NewRootDeleteCollectionActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootDeleteCollectionActionWithOptions"}), + "NewDeleteCollectionActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewDeleteCollectionActionWithOptions"}), + "NewRootUpdateActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootUpdateActionWithOptions"}), + "NewUpdateActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewUpdateActionWithOptions"}), + "NewRootCreateActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootCreateActionWithOptions"}), + "NewCreateActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewCreateActionWithOptions"}), + "NewRootWatchActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootWatchActionWithOptions"}), + "NewWatchActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewWatchActionWithOptions"}), + "NewCreateSubresourceActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewCreateSubresourceActionWithOptions"}), + "NewRootCreateSubresourceActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootCreateSubresourceActionWithOptions"}), + "NewUpdateSubresourceActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewUpdateSubresourceActionWithOptions"}), + "NewGetSubresourceActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewGetSubresourceActionWithOptions"}), + "NewRootGetSubresourceActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootGetSubresourceActionWithOptions"}), + "NewRootUpdateSubresourceActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootUpdateSubresourceActionWithOptions"}), + "NewRootPatchActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootPatchActionWithOptions"}), + "NewPatchActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewPatchActionWithOptions"}), + "NewRootPatchSubresourceActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewRootPatchSubresourceActionWithOptions"}), + "NewPatchSubresourceActionWithOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "NewPatchSubresourceActionWithOptions"}), + "ExtractFromListOptions": c.Universe.Function(types.Name{Package: pkgClientGoTesting, Name: "ExtractFromListOptions"}), + } + + generateApply := len(g.applyConfigurationPackage) > 0 + if generateApply { + // Generated apply builder type references required for generated Apply function + _, gvString := util.ParsePathGroupVersion(g.inputPackage) + m["inputApplyConfig"] = types.Ref(path.Join(g.applyConfigurationPackage, gvString), t.Name.Name+"ApplyConfiguration") + } + + if tags.NonNamespaced { + sw.Do(structNonNamespaced, m) + } else { + sw.Do(structNamespaced, m) + } + + if tags.NoVerbs { + return sw.Error() + } + sw.Do(resource, m) + sw.Do(kind, m) + + if tags.HasVerb("get") { + sw.Do(getTemplate, m) + } + if tags.HasVerb("list") { + if hasObjectMeta(t) { + sw.Do(listUsingOptionsTemplate, m) + } else { + sw.Do(listTemplate, m) + } + } + if tags.HasVerb("watch") { + sw.Do(watchTemplate, m) + } + + if tags.HasVerb("create") { + sw.Do(createTemplate, m) + } + if tags.HasVerb("update") { + sw.Do(updateTemplate, m) + } + if tags.HasVerb("updateStatus") && genStatus(t) { + sw.Do(updateStatusTemplate, m) + } + if tags.HasVerb("delete") { + sw.Do(deleteTemplate, m) + } + if tags.HasVerb("deleteCollection") { + sw.Do(deleteCollectionTemplate, m) + } + if tags.HasVerb("patch") { + sw.Do(patchTemplate, m) + } + if tags.HasVerb("apply") && generateApply { + sw.Do(applyTemplate, m) + } + if tags.HasVerb("applyStatus") && generateApply && genStatus(t) { + sw.Do(applyStatusTemplate, m) + } + _, typeGVString := util.ParsePathGroupVersion(g.inputPackage) + + // generate extended client methods + for _, e := range tags.Extensions { + if e.HasVerb("apply") && !generateApply { + continue + } + inputType := *t + resultType := *t + inputGVString := typeGVString + if len(e.InputTypeOverride) > 0 { + if name, pkg := e.Input(); len(pkg) > 0 { + _, inputGVString = util.ParsePathGroupVersion(pkg) + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + inputType = *newType + } else { + inputType.Name.Name = e.InputTypeOverride + } + } + if len(e.ResultTypeOverride) > 0 { + if name, pkg := e.Result(); len(pkg) > 0 { + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + resultType = *newType + } else { + resultType.Name.Name = e.ResultTypeOverride + } + } + m["inputType"] = &inputType + m["resultType"] = &resultType + m["subresourcePath"] = e.SubResourcePath + if e.HasVerb("apply") { + m["inputApplyConfig"] = types.Ref(path.Join(g.applyConfigurationPackage, inputGVString), inputType.Name.Name+"ApplyConfiguration") + } + + if e.HasVerb("get") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, getSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, getTemplate), m) + } + } + + if e.HasVerb("list") { + + sw.Do(adjustTemplate(e.VerbName, e.VerbType, listTemplate), m) + } + + // TODO: Figure out schemantic for watching a sub-resource. + if e.HasVerb("watch") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, watchTemplate), m) + } + + if e.HasVerb("create") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, createSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, createTemplate), m) + } + } + + if e.HasVerb("update") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateTemplate), m) + } + } + + // TODO: Figure out schemantic for deleting a sub-resource (what arguments + // are passed, does it need two names? etc. + if e.HasVerb("delete") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, deleteTemplate), m) + } + + if e.HasVerb("patch") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, patchTemplate), m) + } + + if e.HasVerb("apply") && generateApply { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, applySubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, applyTemplate), m) + } + } + } + + return sw.Error() +} + +// adjustTemplate adjust the origin verb template using the expansion name. +// TODO: Make the verbs in templates parametrized so the strings.Replace() is +// not needed. +func adjustTemplate(name, verbType, template string) string { + return strings.ReplaceAll(template, " "+titler.String(verbType), " "+name) +} + +// template for the struct that implements the type's interface +var structNamespaced = ` +// Fake$.type|publicPlural$ implements $.type|public$Interface +type Fake$.type|publicPlural$ struct { + Fake *Fake$.GroupGoName$$.Version$ + ns string +} +` + +// template for the struct that implements the type's interface +var structNonNamespaced = ` +// Fake$.type|publicPlural$ implements $.type|public$Interface +type Fake$.type|publicPlural$ struct { + Fake *Fake$.GroupGoName$$.Version$ +} +` + +var resource = ` +var $.type|allLowercasePlural$Resource = $.SchemeGroupVersion|raw$.WithResource("$.type|resource$") +` + +var kind = ` +var $.type|allLowercasePlural$Kind = $.SchemeGroupVersion|raw$.WithKind("$.type|singularKind$") +` + +var listTemplate = ` +// List takes label and field selectors, and returns the list of $.type|publicPlural$ that match those selectors. +func (c *Fake$.type|publicPlural$) List(ctx $.contextContext|raw$, opts $.ListOptions|raw$) (result *$.type|raw$List, err error) { + emptyResult := &$.type|raw$List{} + obj, err := c.Fake. + $if .namespaced$Invokes($.NewListActionWithOptions|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, c.ns, opts), emptyResult) + $else$Invokes($.NewRootListActionWithOptions|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, opts), emptyResult)$end$ + if obj == nil { + return emptyResult, err + } + return obj.(*$.type|raw$List), err +} +` + +var listUsingOptionsTemplate = ` +// List takes label and field selectors, and returns the list of $.type|publicPlural$ that match those selectors. +func (c *Fake$.type|publicPlural$) List(ctx $.contextContext|raw$, opts $.ListOptions|raw$) (result *$.type|raw$List, err error) { + emptyResult := &$.type|raw$List{} + obj, err := c.Fake. + $if .namespaced$Invokes($.NewListActionWithOptions|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, c.ns, opts), emptyResult) + $else$Invokes($.NewRootListActionWithOptions|raw$($.type|allLowercasePlural$Resource, $.type|allLowercasePlural$Kind, opts), emptyResult)$end$ + if obj == nil { + return emptyResult, err + } + + label, _, _ := $.ExtractFromListOptions|raw$(opts) + if label == nil { + label = $.Everything|raw$() + } + list := &$.type|raw$List{ListMeta: obj.(*$.type|raw$List).ListMeta} + for _, item := range obj.(*$.type|raw$List).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} +` + +var getTemplate = ` +// Get takes name of the $.type|private$, and returns the corresponding $.resultType|private$ object, and an error if there is any. +func (c *Fake$.type|publicPlural$) Get(ctx $.contextContext|raw$, name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) { + emptyResult := &$.resultType|raw${} + obj, err := c.Fake. + $if .namespaced$Invokes($.NewGetActionWithOptions|raw$($.type|allLowercasePlural$Resource, c.ns, name, options), emptyResult) + $else$Invokes($.NewRootGetActionWithOptions|raw$($.type|allLowercasePlural$Resource, name, options), emptyResult)$end$ + if obj == nil { + return emptyResult, err + } + return obj.(*$.resultType|raw$), err +} +` + +var getSubresourceTemplate = ` +// Get takes name of the $.type|private$, and returns the corresponding $.resultType|private$ object, and an error if there is any. +func (c *Fake$.type|publicPlural$) Get(ctx $.contextContext|raw$, $.type|private$Name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) { + emptyResult := &$.resultType|raw${} + obj, err := c.Fake. + $if .namespaced$Invokes($.NewGetSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, c.ns, "$.subresourcePath$", $.type|private$Name, options), emptyResult) + $else$Invokes($.NewRootGetSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, "$.subresourcePath$", $.type|private$Name, options), emptyResult)$end$ + if obj == nil { + return emptyResult, err + } + return obj.(*$.resultType|raw$), err +} +` + +var deleteTemplate = ` +// Delete takes name of the $.type|private$ and deletes it. Returns an error if one occurs. +func (c *Fake$.type|publicPlural$) Delete(ctx $.contextContext|raw$, name string, opts $.DeleteOptions|raw$) error { + _, err := c.Fake. + $if .namespaced$Invokes($.NewDeleteActionWithOptions|raw$($.type|allLowercasePlural$Resource, c.ns, name, opts), &$.type|raw${}) + $else$Invokes($.NewRootDeleteActionWithOptions|raw$($.type|allLowercasePlural$Resource, name, opts), &$.type|raw${})$end$ + return err +} +` + +var deleteCollectionTemplate = ` +// DeleteCollection deletes a collection of objects. +func (c *Fake$.type|publicPlural$) DeleteCollection(ctx $.contextContext|raw$, opts $.DeleteOptions|raw$, listOpts $.ListOptions|raw$) error { + $if .namespaced$action := $.NewDeleteCollectionActionWithOptions|raw$($.type|allLowercasePlural$Resource, c.ns, opts, listOpts) + $else$action := $.NewRootDeleteCollectionActionWithOptions|raw$($.type|allLowercasePlural$Resource, opts, listOpts) + $end$ + _, err := c.Fake.Invokes(action, &$.type|raw$List{}) + return err +} +` +var createTemplate = ` +// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *Fake$.type|publicPlural$) Create(ctx $.contextContext|raw$, $.inputType|private$ *$.inputType|raw$, opts $.CreateOptions|raw$) (result *$.resultType|raw$, err error) { + emptyResult := &$.resultType|raw${} + obj, err := c.Fake. + $if .namespaced$Invokes($.NewCreateActionWithOptions|raw$($.inputType|allLowercasePlural$Resource, c.ns, $.inputType|private$, opts), emptyResult) + $else$Invokes($.NewRootCreateActionWithOptions|raw$($.inputType|allLowercasePlural$Resource, $.inputType|private$, opts), emptyResult)$end$ + if obj == nil { + return emptyResult, err + } + return obj.(*$.resultType|raw$), err +} +` + +var createSubresourceTemplate = ` +// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *Fake$.type|publicPlural$) Create(ctx $.contextContext|raw$, $.type|private$Name string, $.inputType|private$ *$.inputType|raw$, opts $.CreateOptions|raw$) (result *$.resultType|raw$, err error) { + emptyResult := &$.resultType|raw${} + obj, err := c.Fake. + $if .namespaced$Invokes($.NewCreateSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, $.type|private$Name, "$.subresourcePath$", c.ns, $.inputType|private$, opts), emptyResult) + $else$Invokes($.NewRootCreateSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, $.type|private$Name, "$.subresourcePath$", $.inputType|private$, opts), emptyResult)$end$ + if obj == nil { + return emptyResult, err + } + return obj.(*$.resultType|raw$), err +} +` + +var updateTemplate = ` +// Update takes the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *Fake$.type|publicPlural$) Update(ctx $.contextContext|raw$, $.inputType|private$ *$.inputType|raw$, opts $.UpdateOptions|raw$) (result *$.resultType|raw$, err error) { + emptyResult := &$.resultType|raw${} + obj, err := c.Fake. + $if .namespaced$Invokes($.NewUpdateActionWithOptions|raw$($.inputType|allLowercasePlural$Resource, c.ns, $.inputType|private$, opts), emptyResult) + $else$Invokes($.NewRootUpdateActionWithOptions|raw$($.inputType|allLowercasePlural$Resource, $.inputType|private$, opts), emptyResult)$end$ + if obj == nil { + return emptyResult, err + } + return obj.(*$.resultType|raw$), err +} +` + +var updateSubresourceTemplate = ` +// Update takes the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *Fake$.type|publicPlural$) Update(ctx $.contextContext|raw$, $.type|private$Name string, $.inputType|private$ *$.inputType|raw$, opts $.UpdateOptions|raw$) (result *$.resultType|raw$, err error) { + emptyResult := &$.resultType|raw${} + obj, err := c.Fake. + $if .namespaced$Invokes($.NewUpdateSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, "$.subresourcePath$", c.ns, $.inputType|private$, opts), &$.inputType|raw${}) + $else$Invokes($.NewRootUpdateSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, "$.subresourcePath$", $.inputType|private$, opts), emptyResult)$end$ + if obj == nil { + return emptyResult, err + } + return obj.(*$.resultType|raw$), err +} +` + +var updateStatusTemplate = ` +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *Fake$.type|publicPlural$) UpdateStatus(ctx $.contextContext|raw$, $.type|private$ *$.type|raw$, opts $.UpdateOptions|raw$) (result *$.type|raw$, err error) { + emptyResult := &$.type|raw${} + obj, err := c.Fake. + $if .namespaced$Invokes($.NewUpdateSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, "status", c.ns, $.type|private$, opts), emptyResult) + $else$Invokes($.NewRootUpdateSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, "status", $.type|private$, opts), emptyResult)$end$ + if obj == nil { + return emptyResult, err + } + return obj.(*$.type|raw$), err +} +` + +var watchTemplate = ` +// Watch returns a $.watchInterface|raw$ that watches the requested $.type|privatePlural$. +func (c *Fake$.type|publicPlural$) Watch(ctx $.contextContext|raw$, opts $.ListOptions|raw$) ($.watchInterface|raw$, error) { + return c.Fake. + $if .namespaced$InvokesWatch($.NewWatchActionWithOptions|raw$($.type|allLowercasePlural$Resource, c.ns, opts)) + $else$InvokesWatch($.NewRootWatchActionWithOptions|raw$($.type|allLowercasePlural$Resource, opts))$end$ +} +` + +var patchTemplate = ` +// Patch applies the patch and returns the patched $.resultType|private$. +func (c *Fake$.type|publicPlural$) Patch(ctx $.contextContext|raw$, name string, pt $.PatchType|raw$, data []byte, opts $.PatchOptions|raw$, subresources ...string) (result *$.resultType|raw$, err error) { + emptyResult := &$.resultType|raw${} + obj, err := c.Fake. + $if .namespaced$Invokes($.NewPatchSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, c.ns, name, pt, data, opts, subresources... ), emptyResult) + $else$Invokes($.NewRootPatchSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, name, pt, data, opts, subresources...), emptyResult)$end$ + if obj == nil { + return emptyResult, err + } + return obj.(*$.resultType|raw$), err +} +` + +var applyTemplate = ` +// Apply takes the given apply declarative configuration, applies it and returns the applied $.resultType|private$. +func (c *Fake$.type|publicPlural$) Apply(ctx $.contextContext|raw$, $.inputType|private$ *$.inputApplyConfig|raw$, opts $.ApplyOptions|raw$) (result *$.resultType|raw$, err error) { + if $.inputType|private$ == nil { + return nil, $.fmtErrorf|raw$("$.inputType|private$ provided to Apply must not be nil") + } + data, err := $.jsonMarshal|raw$($.inputType|private$) + if err != nil { + return nil, err + } + name := $.inputType|private$.Name + if name == nil { + return nil, $.fmtErrorf|raw$("$.inputType|private$.Name must be provided to Apply") + } + emptyResult := &$.resultType|raw${} + obj, err := c.Fake. + $if .namespaced$Invokes($.NewPatchSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, c.ns, *name, $.ApplyPatchType|raw$, data, opts.ToPatchOptions()), emptyResult) + $else$Invokes($.NewRootPatchSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, *name, $.ApplyPatchType|raw$, data, opts.ToPatchOptions()), emptyResult)$end$ + if obj == nil { + return emptyResult, err + } + return obj.(*$.resultType|raw$), err +} +` + +var applyStatusTemplate = ` +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *Fake$.type|publicPlural$) ApplyStatus(ctx $.contextContext|raw$, $.inputType|private$ *$.inputApplyConfig|raw$, opts $.ApplyOptions|raw$) (result *$.resultType|raw$, err error) { + if $.inputType|private$ == nil { + return nil, $.fmtErrorf|raw$("$.inputType|private$ provided to Apply must not be nil") + } + data, err := $.jsonMarshal|raw$($.inputType|private$) + if err != nil { + return nil, err + } + name := $.inputType|private$.Name + if name == nil { + return nil, $.fmtErrorf|raw$("$.inputType|private$.Name must be provided to Apply") + } + emptyResult := &$.resultType|raw${} + obj, err := c.Fake. + $if .namespaced$Invokes($.NewPatchSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, c.ns, *name, $.ApplyPatchType|raw$, data, opts.ToPatchOptions(), "status"), emptyResult) + $else$Invokes($.NewRootPatchSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, *name, $.ApplyPatchType|raw$, data, opts.ToPatchOptions(), "status"), emptyResult)$end$ + if obj == nil { + return emptyResult, err + } + return obj.(*$.resultType|raw$), err +} +` + +var applySubresourceTemplate = ` +// Apply takes top resource name and the apply declarative configuration for $.subresourcePath$, +// applies it and returns the applied $.resultType|private$, and an error, if there is any. +func (c *Fake$.type|publicPlural$) Apply(ctx $.contextContext|raw$, $.type|private$Name string, $.inputType|private$ *$.inputApplyConfig|raw$, opts $.ApplyOptions|raw$) (result *$.resultType|raw$, err error) { + if $.inputType|private$ == nil { + return nil, $.fmtErrorf|raw$("$.inputType|private$ provided to Apply must not be nil") + } + data, err := $.jsonMarshal|raw$($.inputType|private$) + if err != nil { + return nil, err + } + emptyResult := &$.resultType|raw${} + obj, err := c.Fake. + $if .namespaced$Invokes($.NewPatchSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, c.ns, $.type|private$Name, $.ApplyPatchType|raw$, data, opts.ToPatchOptions(), "$.inputType|private$"), emptyResult) + $else$Invokes($.NewRootPatchSubresourceActionWithOptions|raw$($.type|allLowercasePlural$Resource, $.type|private$Name, $.ApplyPatchType|raw$, data, opts.ToPatchOptions(), "$.inputType|private$"), emptyResult)$end$ + if obj == nil { + return emptyResult, err + } + return obj.(*$.resultType|raw$), err +} +` diff --git a/code-generator/cmd/client-gen/generators/generator_for_clientset.go b/code-generator/cmd/client-gen/generators/generator_for_clientset.go new file mode 100644 index 000000000..e84205604 --- /dev/null +++ b/code-generator/cmd/client-gen/generators/generator_for_clientset.go @@ -0,0 +1,210 @@ +/* +Copyright 2016 The Kubernetes 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 ( + "fmt" + "io" + "path" + "strings" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" +) + +// genClientset generates a package for a clientset. +type genClientset struct { + generator.GoGenerator + groups []clientgentypes.GroupVersions + groupGoNames map[clientgentypes.GroupVersion]string + clientsetPackage string // must be a Go import-path + imports namer.ImportTracker + clientsetGenerated bool +} + +var _ generator.Generator = &genClientset{} + +func (g *genClientset) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.clientsetPackage, g.imports), + } +} + +// We only want to call GenerateType() once. +func (g *genClientset) Filter(c *generator.Context, t *types.Type) bool { + ret := !g.clientsetGenerated + g.clientsetGenerated = true + return ret +} + +func (g *genClientset) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + for _, group := range g.groups { + for _, version := range group.Versions { + typedClientPath := path.Join(g.clientsetPackage, "typed", strings.ToLower(group.PackageName), strings.ToLower(version.NonEmpty())) + groupAlias := strings.ToLower(g.groupGoNames[clientgentypes.GroupVersion{Group: group.Group, Version: version.Version}]) + imports = append(imports, fmt.Sprintf("%s%s \"%s\"", groupAlias, strings.ToLower(version.NonEmpty()), typedClientPath)) + } + } + return +} + +func (g *genClientset) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + // TODO: We actually don't need any type information to generate the clientset, + // perhaps we can adapt the go2ild framework to this kind of usage. + sw := generator.NewSnippetWriter(w, c, "$", "$") + + allGroups := clientgentypes.ToGroupVersionInfo(g.groups, g.groupGoNames) + m := map[string]interface{}{ + "allGroups": allGroups, + "fmtErrorf": c.Universe.Type(types.Name{Package: "fmt", Name: "Errorf"}), + "Config": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Config"}), + "DefaultKubernetesUserAgent": c.Universe.Function(types.Name{Package: "k8s.io/client-go/rest", Name: "DefaultKubernetesUserAgent"}), + "RESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}), + "RESTHTTPClientFor": c.Universe.Function(types.Name{Package: "k8s.io/client-go/rest", Name: "HTTPClientFor"}), + "DiscoveryInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/discovery", Name: "DiscoveryInterface"}), + "DiscoveryClient": c.Universe.Type(types.Name{Package: "k8s.io/client-go/discovery", Name: "DiscoveryClient"}), + "httpClient": c.Universe.Type(types.Name{Package: "net/http", Name: "Client"}), + "NewDiscoveryClientForConfigAndClient": c.Universe.Function(types.Name{Package: "k8s.io/client-go/discovery", Name: "NewDiscoveryClientForConfigAndClient"}), + "NewDiscoveryClientForConfigOrDie": c.Universe.Function(types.Name{Package: "k8s.io/client-go/discovery", Name: "NewDiscoveryClientForConfigOrDie"}), + "NewDiscoveryClient": c.Universe.Function(types.Name{Package: "k8s.io/client-go/discovery", Name: "NewDiscoveryClient"}), + "flowcontrolNewTokenBucketRateLimiter": c.Universe.Function(types.Name{Package: "k8s.io/client-go/util/flowcontrol", Name: "NewTokenBucketRateLimiter"}), + } + sw.Do(clientsetInterface, m) + sw.Do(clientsetTemplate, m) + for _, g := range allGroups { + sw.Do(clientsetInterfaceImplTemplate, g) + } + sw.Do(getDiscoveryTemplate, m) + sw.Do(newClientsetForConfigTemplate, m) + sw.Do(newClientsetForConfigAndClientTemplate, m) + sw.Do(newClientsetForConfigOrDieTemplate, m) + sw.Do(newClientsetForRESTClientTemplate, m) + + return sw.Error() +} + +var clientsetInterface = ` +type Interface interface { + Discovery() $.DiscoveryInterface|raw$ + $range .allGroups$$.GroupGoName$$.Version$() $.PackageAlias$.$.GroupGoName$$.Version$Interface + $end$ +} +` + +var clientsetTemplate = ` +// Clientset contains the clients for groups. +type Clientset struct { + *$.DiscoveryClient|raw$ + $range .allGroups$$.LowerCaseGroupGoName$$.Version$ *$.PackageAlias$.$.GroupGoName$$.Version$Client + $end$ +} +` + +var clientsetInterfaceImplTemplate = ` +// $.GroupGoName$$.Version$ retrieves the $.GroupGoName$$.Version$Client +func (c *Clientset) $.GroupGoName$$.Version$() $.PackageAlias$.$.GroupGoName$$.Version$Interface { + return c.$.LowerCaseGroupGoName$$.Version$ +} +` + +var getDiscoveryTemplate = ` +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() $.DiscoveryInterface|raw$ { + if c == nil { + return nil + } + return c.DiscoveryClient +} +` + +var newClientsetForConfigTemplate = ` +// NewForConfig creates a new Clientset for the given config. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfig will generate a rate-limiter in configShallowCopy. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *$.Config|raw$) (*Clientset, error) { + configShallowCopy := *c + + if configShallowCopy.UserAgent == "" { + configShallowCopy.UserAgent = $.DefaultKubernetesUserAgent|raw$() + } + + // share the transport between all clients + httpClient, err := $.RESTHTTPClientFor|raw$(&configShallowCopy) + if err != nil { + return nil, err + } + + return NewForConfigAndClient(&configShallowCopy, httpClient) +} +` + +var newClientsetForConfigAndClientTemplate = ` +// NewForConfigAndClient creates a new Clientset for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfigAndClient will generate a rate-limiter in configShallowCopy. +func NewForConfigAndClient(c *$.Config|raw$, httpClient *$.httpClient|raw$) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + if configShallowCopy.Burst <= 0 { + return nil, $.fmtErrorf|raw$("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") + } + configShallowCopy.RateLimiter = $.flowcontrolNewTokenBucketRateLimiter|raw$(configShallowCopy.QPS, configShallowCopy.Burst) + } + + var cs Clientset + var err error +$range .allGroups$ cs.$.LowerCaseGroupGoName$$.Version$, err =$.PackageAlias$.NewForConfigAndClient(&configShallowCopy, httpClient) + if err!=nil { + return nil, err + } +$end$ + cs.DiscoveryClient, err = $.NewDiscoveryClientForConfigAndClient|raw$(&configShallowCopy, httpClient) + if err!=nil { + return nil, err + } + return &cs, nil +} +` + +var newClientsetForConfigOrDieTemplate = ` +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *$.Config|raw$) *Clientset { + cs, err := NewForConfig(c) + if err!=nil { + panic(err) + } + return cs +} +` + +var newClientsetForRESTClientTemplate = ` +// New creates a new Clientset for the given RESTClient. +func New(c $.RESTClientInterface|raw$) *Clientset { + var cs Clientset +$range .allGroups$ cs.$.LowerCaseGroupGoName$$.Version$ =$.PackageAlias$.New(c) +$end$ + cs.DiscoveryClient = $.NewDiscoveryClient|raw$(c) + return &cs +} +` diff --git a/code-generator/cmd/client-gen/generators/generator_for_expansion.go b/code-generator/cmd/client-gen/generators/generator_for_expansion.go new file mode 100644 index 000000000..5971cc5bc --- /dev/null +++ b/code-generator/cmd/client-gen/generators/generator_for_expansion.go @@ -0,0 +1,54 @@ +/* +Copyright 2016 The Kubernetes 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" + "os" + "path/filepath" + "strings" + + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/types" +) + +// genExpansion produces a file for a group client, e.g. ExtensionsClient for the extension group. +type genExpansion struct { + generator.GoGenerator + groupPackagePath string + // types in a group + types []*types.Type +} + +// We only want to call GenerateType() once per group. +func (g *genExpansion) Filter(c *generator.Context, t *types.Type) bool { + return len(g.types) == 0 || t == g.types[0] +} + +func (g *genExpansion) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + for _, t := range g.types { + if _, err := os.Stat(filepath.Join(g.groupPackagePath, strings.ToLower(t.Name.Name+"_expansion.go"))); os.IsNotExist(err) { + sw.Do(expansionInterfaceTemplate, t) + } + } + return sw.Error() +} + +var expansionInterfaceTemplate = ` +type $.|public$Expansion interface {} +` diff --git a/code-generator/cmd/client-gen/generators/generator_for_group.go b/code-generator/cmd/client-gen/generators/generator_for_group.go new file mode 100644 index 000000000..e5915b677 --- /dev/null +++ b/code-generator/cmd/client-gen/generators/generator_for_group.go @@ -0,0 +1,264 @@ +/* +Copyright 2015 The Kubernetes 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" + "path" + + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + + "k8s.io/code-generator/cmd/client-gen/generators/util" +) + +// genGroup produces a file for a group client, e.g. ExtensionsClient for the extension group. +type genGroup struct { + generator.GoGenerator + outputPackage string + group string + version string + groupGoName string + apiPath string + // types in this group + types []*types.Type + imports namer.ImportTracker + inputPackage string + clientsetPackage string // must be a Go import-path + // If the genGroup has been called. This generator should only execute once. + called bool +} + +var _ generator.Generator = &genGroup{} + +// We only want to call GenerateType() once per group. +func (g *genGroup) Filter(c *generator.Context, t *types.Type) bool { + if !g.called { + g.called = true + return true + } + return false +} + +func (g *genGroup) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *genGroup) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *genGroup) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + + // allow user to define a group name that's different from the one parsed from the directory. + p := c.Universe.Package(g.inputPackage) + groupName := g.group + if override := gengo.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil { + groupName = override[0] + } + + apiPath := `"` + g.apiPath + `"` + if groupName == "" { + apiPath = `"/api"` + } + schemePackage := path.Join(g.clientsetPackage, "scheme") + m := map[string]interface{}{ + "version": g.version, + "groupName": groupName, + "GroupGoName": g.groupGoName, + "Version": namer.IC(g.version), + "types": g.types, + "apiPath": apiPath, + "httpClient": c.Universe.Type(types.Name{Package: "net/http", Name: "Client"}), + "schemaGroupVersion": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersion"}), + "runtimeAPIVersionInternal": c.Universe.Variable(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "APIVersionInternal"}), + "restConfig": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Config"}), + "restDefaultKubernetesUserAgent": c.Universe.Function(types.Name{Package: "k8s.io/client-go/rest", Name: "DefaultKubernetesUserAgent"}), + "restRESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}), + "RESTHTTPClientFor": c.Universe.Function(types.Name{Package: "k8s.io/client-go/rest", Name: "HTTPClientFor"}), + "restRESTClientFor": c.Universe.Function(types.Name{Package: "k8s.io/client-go/rest", Name: "RESTClientFor"}), + "restRESTClientForConfigAndClient": c.Universe.Function(types.Name{Package: "k8s.io/client-go/rest", Name: "RESTClientForConfigAndClient"}), + "SchemeGroupVersion": c.Universe.Variable(types.Name{Package: g.inputPackage, Name: "SchemeGroupVersion"}), + "SchemePrioritizedVersionsForGroup": c.Universe.Variable(types.Name{Package: schemePackage, Name: "Scheme.PrioritizedVersionsForGroup"}), + "Codecs": c.Universe.Variable(types.Name{Package: schemePackage, Name: "Codecs"}), + "CodecsWithoutConversion": c.Universe.Variable(types.Name{Package: schemePackage, Name: "Codecs.WithoutConversion"}), + } + sw.Do(groupInterfaceTemplate, m) + sw.Do(groupClientTemplate, m) + for _, t := range g.types { + tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if err != nil { + return err + } + wrapper := map[string]interface{}{ + "type": t, + "GroupGoName": g.groupGoName, + "Version": namer.IC(g.version), + } + if tags.NonNamespaced { + sw.Do(getterImplNonNamespaced, wrapper) + } else { + sw.Do(getterImplNamespaced, wrapper) + } + } + sw.Do(newClientForConfigTemplate, m) + sw.Do(newClientForConfigAndClientTemplate, m) + sw.Do(newClientForConfigOrDieTemplate, m) + sw.Do(newClientForRESTClientTemplate, m) + if g.version == "" { + sw.Do(setInternalVersionClientDefaultsTemplate, m) + } else { + sw.Do(setClientDefaultsTemplate, m) + } + sw.Do(getRESTClient, m) + + return sw.Error() +} + +var groupInterfaceTemplate = ` +type $.GroupGoName$$.Version$Interface interface { + RESTClient() $.restRESTClientInterface|raw$ + $range .types$ $.|publicPlural$Getter + $end$ +} +` + +var groupClientTemplate = ` +// $.GroupGoName$$.Version$Client is used to interact with features provided by the $.groupName$ group. +type $.GroupGoName$$.Version$Client struct { + restClient $.restRESTClientInterface|raw$ +} +` + +var getterImplNamespaced = ` +func (c *$.GroupGoName$$.Version$Client) $.type|publicPlural$(namespace string) $.type|public$Interface { + return new$.type|publicPlural$(c, namespace) +} +` + +var getterImplNonNamespaced = ` +func (c *$.GroupGoName$$.Version$Client) $.type|publicPlural$() $.type|public$Interface { + return new$.type|publicPlural$(c) +} +` + +var newClientForConfigTemplate = ` +// NewForConfig creates a new $.GroupGoName$$.Version$Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *$.restConfig|raw$) (*$.GroupGoName$$.Version$Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + httpClient, err := $.RESTHTTPClientFor|raw$(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} +` + +var newClientForConfigAndClientTemplate = ` +// NewForConfigAndClient creates a new $.GroupGoName$$.Version$Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *$.restConfig|raw$, h *$.httpClient|raw$) (*$.GroupGoName$$.Version$Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := $.restRESTClientForConfigAndClient|raw$(&config, h) + if err != nil { + return nil, err + } + return &$.GroupGoName$$.Version$Client{client}, nil +} +` + +var newClientForConfigOrDieTemplate = ` +// NewForConfigOrDie creates a new $.GroupGoName$$.Version$Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *$.restConfig|raw$) *$.GroupGoName$$.Version$Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} +` + +var getRESTClient = ` +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *$.GroupGoName$$.Version$Client) RESTClient() $.restRESTClientInterface|raw$ { + if c == nil { + return nil + } + return c.restClient +} +` + +var newClientForRESTClientTemplate = ` +// New creates a new $.GroupGoName$$.Version$Client for the given RESTClient. +func New(c $.restRESTClientInterface|raw$) *$.GroupGoName$$.Version$Client { + return &$.GroupGoName$$.Version$Client{c} +} +` + +var setInternalVersionClientDefaultsTemplate = ` +func setConfigDefaults(config *$.restConfig|raw$) error { + config.APIPath = $.apiPath$ + if config.UserAgent == "" { + config.UserAgent = $.restDefaultKubernetesUserAgent|raw$() + } + if config.GroupVersion == nil || config.GroupVersion.Group != $.SchemePrioritizedVersionsForGroup|raw$("$.groupName$")[0].Group { + gv := $.SchemePrioritizedVersionsForGroup|raw$("$.groupName$")[0] + config.GroupVersion = &gv + } + config.NegotiatedSerializer = $.Codecs|raw$ + + if config.QPS == 0 { + config.QPS = 5 + } + if config.Burst == 0 { + config.Burst = 10 + } + + return nil +} +` + +var setClientDefaultsTemplate = ` +func setConfigDefaults(config *$.restConfig|raw$) error { + gv := $.SchemeGroupVersion|raw$ + config.GroupVersion = &gv + config.APIPath = $.apiPath$ + config.NegotiatedSerializer = $.CodecsWithoutConversion|raw$() + + if config.UserAgent == "" { + config.UserAgent = $.restDefaultKubernetesUserAgent|raw$() + } + + return nil +} +` diff --git a/code-generator/cmd/client-gen/generators/generator_for_type.go b/code-generator/cmd/client-gen/generators/generator_for_type.go new file mode 100644 index 000000000..ce307e5ec --- /dev/null +++ b/code-generator/cmd/client-gen/generators/generator_for_type.go @@ -0,0 +1,860 @@ +/* +Copyright 2015 The Kubernetes 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" + "path" + "strings" + + "golang.org/x/text/cases" + "golang.org/x/text/language" + + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + + "k8s.io/code-generator/cmd/client-gen/generators/util" +) + +// genClientForType produces a file for each top-level type. +type genClientForType struct { + generator.GoGenerator + outputPackage string // must be a Go import-path + inputPackage string + clientsetPackage string // must be a Go import-path + applyConfigurationPackage string // must be a Go import-path + group string + version string + groupGoName string + typeToMatch *types.Type + imports namer.ImportTracker +} + +var _ generator.Generator = &genClientForType{} + +var titler = cases.Title(language.Und) + +// Filter ignores all but one type because we're making a single file per type. +func (g *genClientForType) Filter(c *generator.Context, t *types.Type) bool { + return t == g.typeToMatch +} + +func (g *genClientForType) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *genClientForType) Imports(c *generator.Context) (imports []string) { + return g.imports.ImportLines() +} + +// Ideally, we'd like genStatus to return true if there is a subresource path +// registered for "status" in the API server, but we do not have that +// information, so genStatus returns true if the type has a status field. +func genStatus(t *types.Type) bool { + // Default to true if we have a Status member + hasStatus := false + for _, m := range t.Members { + if m.Name == "Status" { + hasStatus = true + break + } + } + return hasStatus && !util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)).NoStatus +} + +// GenerateType makes the body of a file implementing the individual typed client for type t. +func (g *genClientForType) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + generateApply := len(g.applyConfigurationPackage) > 0 + defaultVerbTemplates := buildDefaultVerbTemplates(generateApply) + subresourceDefaultVerbTemplates := buildSubresourceDefaultVerbTemplates(generateApply) + sw := generator.NewSnippetWriter(w, c, "$", "$") + pkg := path.Base(t.Name.Package) + tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if err != nil { + return err + } + type extendedInterfaceMethod struct { + template string + args map[string]interface{} + } + _, typeGVString := util.ParsePathGroupVersion(g.inputPackage) + extendedMethods := []extendedInterfaceMethod{} + for _, e := range tags.Extensions { + if e.HasVerb("apply") && !generateApply { + continue + } + inputType := *t + resultType := *t + inputGVString := typeGVString + // TODO: Extract this to some helper method as this code is copied into + // 2 other places. + if len(e.InputTypeOverride) > 0 { + if name, pkg := e.Input(); len(pkg) > 0 { + _, inputGVString = util.ParsePathGroupVersion(pkg) + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + inputType = *newType + } else { + inputType.Name.Name = e.InputTypeOverride + } + } + if len(e.ResultTypeOverride) > 0 { + if name, pkg := e.Result(); len(pkg) > 0 { + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + resultType = *newType + } else { + resultType.Name.Name = e.ResultTypeOverride + } + } + var updatedVerbtemplate string + if _, exists := subresourceDefaultVerbTemplates[e.VerbType]; e.IsSubresource() && exists { + updatedVerbtemplate = e.VerbName + "(" + strings.TrimPrefix(subresourceDefaultVerbTemplates[e.VerbType], titler.String(e.VerbType)+"(") + } else { + updatedVerbtemplate = e.VerbName + "(" + strings.TrimPrefix(defaultVerbTemplates[e.VerbType], titler.String(e.VerbType)+"(") + } + extendedMethod := extendedInterfaceMethod{ + template: updatedVerbtemplate, + args: map[string]interface{}{ + "type": t, + "inputType": &inputType, + "resultType": &resultType, + "CreateOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "CreateOptions"}), + "GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}), + "ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}), + "UpdateOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "UpdateOptions"}), + "ApplyOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ApplyOptions"}), + "PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}), + "jsonMarshal": c.Universe.Type(types.Name{Package: "encoding/json", Name: "Marshal"}), + "context": c.Universe.Type(types.Name{Package: "context", Name: "Context"}), + }, + } + if e.HasVerb("apply") { + extendedMethod.args["inputApplyConfig"] = types.Ref(path.Join(g.applyConfigurationPackage, inputGVString), inputType.Name.Name+"ApplyConfiguration") + } + extendedMethods = append(extendedMethods, extendedMethod) + } + m := map[string]interface{}{ + "type": t, + "inputType": t, + "resultType": t, + "package": pkg, + "Package": namer.IC(pkg), + "namespaced": !tags.NonNamespaced, + "Group": namer.IC(g.group), + "subresource": false, + "subresourcePath": "", + "GroupGoName": g.groupGoName, + "Version": namer.IC(g.version), + "CreateOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "CreateOptions"}), + "DeleteOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "DeleteOptions"}), + "GetOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GetOptions"}), + "ListOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"}), + "PatchOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "PatchOptions"}), + "ApplyOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ApplyOptions"}), + "UpdateOptions": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "UpdateOptions"}), + "PatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "PatchType"}), + "ApplyPatchType": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/types", Name: "ApplyPatchType"}), + "watchInterface": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"}), + "RESTClientInterface": c.Universe.Type(types.Name{Package: "k8s.io/client-go/rest", Name: "Interface"}), + "schemeParameterCodec": c.Universe.Variable(types.Name{Package: path.Join(g.clientsetPackage, "scheme"), Name: "ParameterCodec"}), + "jsonMarshal": c.Universe.Type(types.Name{Package: "encoding/json", Name: "Marshal"}), + "fmtErrorf": c.Universe.Type(types.Name{Package: "fmt", Name: "Errorf"}), + "context": c.Universe.Type(types.Name{Package: "context", Name: "Context"}), + "resourceVersionMatchNotOlderThan": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ResourceVersionMatchNotOlderThan"}), + "CheckListFromCacheDataConsistencyIfRequested": c.Universe.Function(types.Name{Package: "k8s.io/client-go/util/consistencydetector", Name: "CheckListFromCacheDataConsistencyIfRequested"}), + "CheckWatchListFromCacheDataConsistencyIfRequested": c.Universe.Function(types.Name{Package: "k8s.io/client-go/util/consistencydetector", Name: "CheckWatchListFromCacheDataConsistencyIfRequested"}), + "PrepareWatchListOptionsFromListOptions": c.Universe.Function(types.Name{Package: "k8s.io/client-go/util/watchlist", Name: "PrepareWatchListOptionsFromListOptions"}), + "Client": c.Universe.Type(types.Name{Package: "k8s.io/client-go/gentype", Name: "Client"}), + "ClientWithList": c.Universe.Type(types.Name{Package: "k8s.io/client-go/gentype", Name: "ClientWithList"}), + "ClientWithApply": c.Universe.Type(types.Name{Package: "k8s.io/client-go/gentype", Name: "ClientWithApply"}), + "ClientWithListAndApply": c.Universe.Type(types.Name{Package: "k8s.io/client-go/gentype", Name: "ClientWithListAndApply"}), + } + + if generateApply { + // Generated apply configuration type references required for generated Apply function + _, gvString := util.ParsePathGroupVersion(g.inputPackage) + m["inputApplyConfig"] = types.Ref(path.Join(g.applyConfigurationPackage, gvString), t.Name.Name+"ApplyConfiguration") + } + + sw.Do(getterComment, m) + if tags.NonNamespaced { + sw.Do(getterNonNamespaced, m) + } else { + sw.Do(getterNamespaced, m) + } + + sw.Do(interfaceTemplate1, m) + if !tags.NoVerbs { + if !genStatus(t) { + tags.SkipVerbs = append(tags.SkipVerbs, "updateStatus") + tags.SkipVerbs = append(tags.SkipVerbs, "applyStatus") + } + interfaceSuffix := "" + if len(extendedMethods) > 0 { + interfaceSuffix = "\n" + } + sw.Do("\n"+generateInterface(defaultVerbTemplates, tags)+interfaceSuffix, m) + // add extended verbs into interface + for _, v := range extendedMethods { + sw.Do(v.template+interfaceSuffix, v.args) + } + + } + sw.Do(interfaceTemplate4, m) + + structNamespaced := namespaced + if tags.NonNamespaced { + structNamespaced = nonNamespaced + } + + if tags.NoVerbs { + sw.Do(structType[noList|noApply], m) + sw.Do(newStruct[structNamespaced|noList|noApply], m) + + return sw.Error() + } + + listableOrAppliable := noList | noApply + + if tags.HasVerb("list") { + listableOrAppliable |= withList + } + + if tags.HasVerb("apply") && generateApply { + listableOrAppliable |= withApply + } + + sw.Do(structType[listableOrAppliable], m) + sw.Do(newStruct[structNamespaced|listableOrAppliable], m) + + // generate expansion methods + for _, e := range tags.Extensions { + if e.HasVerb("apply") && !generateApply { + continue + } + inputType := *t + resultType := *t + inputGVString := typeGVString + if len(e.InputTypeOverride) > 0 { + if name, pkg := e.Input(); len(pkg) > 0 { + _, inputGVString = util.ParsePathGroupVersion(pkg) + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + inputType = *newType + } else { + inputType.Name.Name = e.InputTypeOverride + } + } + if len(e.ResultTypeOverride) > 0 { + if name, pkg := e.Result(); len(pkg) > 0 { + newType := c.Universe.Type(types.Name{Package: pkg, Name: name}) + resultType = *newType + } else { + resultType.Name.Name = e.ResultTypeOverride + } + } + m["inputType"] = &inputType + m["resultType"] = &resultType + m["subresourcePath"] = e.SubResourcePath + if e.HasVerb("apply") { + m["inputApplyConfig"] = types.Ref(path.Join(g.applyConfigurationPackage, inputGVString), inputType.Name.Name+"ApplyConfiguration") + } + + if e.HasVerb("get") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, getSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, getTemplate), m) + } + } + + if e.HasVerb("list") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, listSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, listTemplate), m) + sw.Do(adjustTemplate(e.VerbName, e.VerbType, privateListTemplate), m) + sw.Do(adjustTemplate(e.VerbName, e.VerbType, watchListTemplate), m) + } + } + + // TODO: Figure out schemantic for watching a sub-resource. + if e.HasVerb("watch") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, watchTemplate), m) + } + + if e.HasVerb("create") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, createSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, createTemplate), m) + } + } + + if e.HasVerb("update") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateSubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, updateTemplate), m) + } + } + + // TODO: Figure out schemantic for deleting a sub-resource (what arguments + // are passed, does it need two names? etc. + if e.HasVerb("delete") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, deleteTemplate), m) + } + + if e.HasVerb("patch") { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, patchTemplate), m) + } + + if e.HasVerb("apply") { + if e.IsSubresource() { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, applySubresourceTemplate), m) + } else { + sw.Do(adjustTemplate(e.VerbName, e.VerbType, applyTemplate), m) + } + } + } + + return sw.Error() +} + +// adjustTemplate adjust the origin verb template using the expansion name. +// TODO: Make the verbs in templates parametrized so the strings.Replace() is +// not needed. +func adjustTemplate(name, verbType, template string) string { + return strings.ReplaceAll(template, " "+titler.String(verbType), " "+name) +} + +func generateInterface(defaultVerbTemplates map[string]string, tags util.Tags) string { + // need an ordered list here to guarantee order of generated methods. + out := []string{} + for _, m := range util.SupportedVerbs { + if tags.HasVerb(m) && len(defaultVerbTemplates[m]) > 0 { + out = append(out, defaultVerbTemplates[m]) + } + } + return strings.Join(out, "\n") +} + +func buildSubresourceDefaultVerbTemplates(generateApply bool) map[string]string { + m := map[string]string{ + "create": `Create(ctx $.context|raw$, $.type|private$Name string, $.inputType|private$ *$.inputType|raw$, opts $.CreateOptions|raw$) (*$.resultType|raw$, error)`, + "list": `List(ctx $.context|raw$, $.type|private$Name string, opts $.ListOptions|raw$) (*$.resultType|raw$List, error)`, + "update": `Update(ctx $.context|raw$, $.type|private$Name string, $.inputType|private$ *$.inputType|raw$, opts $.UpdateOptions|raw$) (*$.resultType|raw$, error)`, + "get": `Get(ctx $.context|raw$, $.type|private$Name string, options $.GetOptions|raw$) (*$.resultType|raw$, error)`, + } + if generateApply { + m["apply"] = `Apply(ctx $.context|raw$, $.type|private$Name string, $.inputType|private$ *$.inputApplyConfig|raw$, opts $.ApplyOptions|raw$) (*$.resultType|raw$, error)` + } + return m +} + +func buildDefaultVerbTemplates(generateApply bool) map[string]string { + m := map[string]string{ + "create": `Create(ctx $.context|raw$, $.inputType|private$ *$.inputType|raw$, opts $.CreateOptions|raw$) (*$.resultType|raw$, error)`, + "update": `Update(ctx $.context|raw$, $.inputType|private$ *$.inputType|raw$, opts $.UpdateOptions|raw$) (*$.resultType|raw$, error)`, + "updateStatus": `// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +UpdateStatus(ctx $.context|raw$, $.inputType|private$ *$.type|raw$, opts $.UpdateOptions|raw$) (*$.type|raw$, error)`, + "delete": `Delete(ctx $.context|raw$, name string, opts $.DeleteOptions|raw$) error`, + "deleteCollection": `DeleteCollection(ctx $.context|raw$, opts $.DeleteOptions|raw$, listOpts $.ListOptions|raw$) error`, + "get": `Get(ctx $.context|raw$, name string, opts $.GetOptions|raw$) (*$.resultType|raw$, error)`, + "list": `List(ctx $.context|raw$, opts $.ListOptions|raw$) (*$.resultType|raw$List, error)`, + "watch": `Watch(ctx $.context|raw$, opts $.ListOptions|raw$) ($.watchInterface|raw$, error)`, + "patch": `Patch(ctx $.context|raw$, name string, pt $.PatchType|raw$, data []byte, opts $.PatchOptions|raw$, subresources ...string) (result *$.resultType|raw$, err error)`, + } + if generateApply { + m["apply"] = `Apply(ctx $.context|raw$, $.inputType|private$ *$.inputApplyConfig|raw$, opts $.ApplyOptions|raw$) (result *$.resultType|raw$, err error)` + m["applyStatus"] = `// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +ApplyStatus(ctx $.context|raw$, $.inputType|private$ *$.inputApplyConfig|raw$, opts $.ApplyOptions|raw$) (result *$.resultType|raw$, err error)` + } + return m +} + +// group client will implement this interface. +var getterComment = ` +// $.type|publicPlural$Getter has a method to return a $.type|public$Interface. +// A group's client should implement this interface.` + +var getterNamespaced = ` +type $.type|publicPlural$Getter interface { + $.type|publicPlural$(namespace string) $.type|public$Interface +} +` + +var getterNonNamespaced = ` +type $.type|publicPlural$Getter interface { + $.type|publicPlural$() $.type|public$Interface +} +` + +// this type's interface, typed client will implement this interface. +var interfaceTemplate1 = ` +// $.type|public$Interface has methods to work with $.type|public$ resources. +type $.type|public$Interface interface {` + +var interfaceTemplate4 = ` + $.type|public$Expansion +} +` + +// struct and constructor variants +const ( + // The following values are bits in a bitmask. + // The values which can be set indicate namespace support, list support, and apply support; + // to make the declarations easier to read (like a truth table), corresponding zero-values + // are also declared. + namespaced = 0 + noList = 0 + noApply = 0 + nonNamespaced = 1 << iota + withList + withApply +) + +// The following string slices are similar to maps, but with combinable keys used as indices. +// Each entry defines whether it supports lists and/or apply, and if namespacedness matters, +// namespaces; each bit is then toggled: +// * noList, noApply: index 0; +// * withList, noApply: index 2; +// * noList, withApply: index 4; +// * withList, withApply: index 6. +// When namespacedness matters, the namespaced variants are the same as the above, and +// the non-namespaced variants are offset by 1. +// Go enforces index unicity in these kinds of declarations. + +// struct declarations +// Namespacedness does not matter +var structType = []string{ + noList | noApply: ` + // $.type|privatePlural$ implements $.type|public$Interface + type $.type|privatePlural$ struct { + *$.Client|raw$[*$.resultType|raw$] + } + `, + withList | noApply: ` + // $.type|privatePlural$ implements $.type|public$Interface + type $.type|privatePlural$ struct { + *$.ClientWithList|raw$[*$.resultType|raw$, *$.resultType|raw$List] + } + `, + noList | withApply: ` + // $.type|privatePlural$ implements $.type|public$Interface + type $.type|privatePlural$ struct { + *$.ClientWithApply|raw$[*$.resultType|raw$, *$.inputApplyConfig|raw$] + } + `, + withList | withApply: ` + // $.type|privatePlural$ implements $.type|public$Interface + type $.type|privatePlural$ struct { + *$.ClientWithListAndApply|raw$[*$.resultType|raw$, *$.resultType|raw$List, *$.inputApplyConfig|raw$] + } + `, +} + +// Constructors for the struct, in all variants +// Namespacedness matters +var newStruct = []string{ + namespaced | noList | noApply: ` + // new$.type|publicPlural$ returns a $.type|publicPlural$ + func new$.type|publicPlural$(c *$.GroupGoName$$.Version$Client, namespace string) *$.type|privatePlural$ { + return &$.type|privatePlural${ + gentype.NewClient[*$.resultType|raw$]( + "$.type|resource$", + c.RESTClient(), + $.schemeParameterCodec|raw$, + namespace, + func() *$.resultType|raw$ { return &$.resultType|raw${} }), + } + } + `, + namespaced | noList | withApply: ` + // new$.type|publicPlural$ returns a $.type|publicPlural$ + func new$.type|publicPlural$(c *$.GroupGoName$$.Version$Client, namespace string) *$.type|privatePlural$ { + return &$.type|privatePlural${ + gentype.NewClientWithApply[*$.resultType|raw$, *$.inputApplyConfig|raw$]( + "$.type|resource$", + c.RESTClient(), + $.schemeParameterCodec|raw$, + namespace, + func() *$.resultType|raw$ { return &$.resultType|raw${} }), + } + } + `, + namespaced | withList | noApply: ` + // new$.type|publicPlural$ returns a $.type|publicPlural$ + func new$.type|publicPlural$(c *$.GroupGoName$$.Version$Client, namespace string) *$.type|privatePlural$ { + return &$.type|privatePlural${ + gentype.NewClientWithList[*$.resultType|raw$, *$.resultType|raw$List]( + "$.type|resource$", + c.RESTClient(), + $.schemeParameterCodec|raw$, + namespace, + func() *$.resultType|raw$ { return &$.resultType|raw${} }, + func() *$.resultType|raw$List { return &$.resultType|raw$List{} }), + } + } + `, + namespaced | withList | withApply: ` + // new$.type|publicPlural$ returns a $.type|publicPlural$ + func new$.type|publicPlural$(c *$.GroupGoName$$.Version$Client, namespace string) *$.type|privatePlural$ { + return &$.type|privatePlural${ + gentype.NewClientWithListAndApply[*$.resultType|raw$, *$.resultType|raw$List, *$.inputApplyConfig|raw$]( + "$.type|resource$", + c.RESTClient(), + $.schemeParameterCodec|raw$, + namespace, + func() *$.resultType|raw$ { return &$.resultType|raw${} }, + func() *$.resultType|raw$List { return &$.resultType|raw$List{} }), + } + } + `, + nonNamespaced | noList | noApply: ` + // new$.type|publicPlural$ returns a $.type|publicPlural$ + func new$.type|publicPlural$(c *$.GroupGoName$$.Version$Client) *$.type|privatePlural$ { + return &$.type|privatePlural${ + gentype.NewClient[*$.resultType|raw$]( + "$.type|resource$", + c.RESTClient(), + $.schemeParameterCodec|raw$, + "", + func() *$.resultType|raw$ { return &$.resultType|raw${} }), + } + } + `, + nonNamespaced | noList | withApply: ` + // new$.type|publicPlural$ returns a $.type|publicPlural$ + func new$.type|publicPlural$(c *$.GroupGoName$$.Version$Client) *$.type|privatePlural$ { + return &$.type|privatePlural${ + gentype.NewClientWithApply[*$.resultType|raw$, *$.inputApplyConfig|raw$]( + "$.type|resource$", + c.RESTClient(), + $.schemeParameterCodec|raw$, + "", + func() *$.resultType|raw$ { return &$.resultType|raw${} }), + } + } + `, + nonNamespaced | withList | noApply: ` + // new$.type|publicPlural$ returns a $.type|publicPlural$ + func new$.type|publicPlural$(c *$.GroupGoName$$.Version$Client) *$.type|privatePlural$ { + return &$.type|privatePlural${ + gentype.NewClientWithList[*$.resultType|raw$, *$.resultType|raw$List]( + "$.type|resource$", + c.RESTClient(), + $.schemeParameterCodec|raw$, + "", + func() *$.resultType|raw$ { return &$.resultType|raw${} }, + func() *$.resultType|raw$List { return &$.resultType|raw$List{} }), + } + } + `, + nonNamespaced | withList | withApply: ` + // new$.type|publicPlural$ returns a $.type|publicPlural$ + func new$.type|publicPlural$(c *$.GroupGoName$$.Version$Client) *$.type|privatePlural$ { + return &$.type|privatePlural${ + gentype.NewClientWithListAndApply[*$.resultType|raw$, *$.resultType|raw$List, *$.inputApplyConfig|raw$]( + "$.type|resource$", + c.RESTClient(), + $.schemeParameterCodec|raw$, + "", + func() *$.resultType|raw$ { return &$.resultType|raw${} }, + func() *$.resultType|raw$List { return &$.resultType|raw$List{} }), + } + } + `, +} + +var listTemplate = ` +// List takes label and field selectors, and returns the list of $.resultType|publicPlural$ that match those selectors. +func (c *$.type|privatePlural$) List(ctx $.context|raw$, opts $.ListOptions|raw$) (*$.resultType|raw$List, error) { + if watchListOptions, hasWatchListOptionsPrepared, watchListOptionsErr := $.PrepareWatchListOptionsFromListOptions|raw$(opts); watchListOptionsErr != nil { + klog.Warningf("Failed preparing watchlist options for $.type|resource$, falling back to the standard LIST semantics, err = %v", watchListOptionsErr ) + } else if hasWatchListOptionsPrepared { + result, err := c.watchList(ctx, watchListOptions) + if err == nil { + $.CheckWatchListFromCacheDataConsistencyIfRequested|raw$(ctx, "watchlist request for $.type|resource$", c.list, opts, result) + return result, nil + } + klog.Warningf("The watchlist request for $.type|resource$ ended with an error, falling back to the standard LIST semantics, err = %v", err) + } + result, err := c.list(ctx, opts) + if err == nil { + $.CheckListFromCacheDataConsistencyIfRequested|raw$(ctx, "list request for $.type|resource$", c.list, opts, result) + } + return result, err +} +` + +var privateListTemplate = ` +// list takes label and field selectors, and returns the list of $.resultType|publicPlural$ that match those selectors. +func (c *$.type|privatePlural$) list(ctx $.context|raw$, opts $.ListOptions|raw$) (result *$.resultType|raw$List, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil{ + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &$.resultType|raw$List{} + err = c.GetClient().Get(). + $if .namespaced$Namespace(c.GetNamespace()).$end$ + Resource("$.type|resource$"). + VersionedParams(&opts, $.schemeParameterCodec|raw$). + Timeout(timeout). + Do(ctx). + Into(result) + return +} +` + +var listSubresourceTemplate = ` +// List takes $.type|raw$ name, label and field selectors, and returns the list of $.resultType|publicPlural$ that match those selectors. +func (c *$.type|privatePlural$) List(ctx $.context|raw$, $.type|private$Name string, opts $.ListOptions|raw$) (result *$.resultType|raw$List, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil{ + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &$.resultType|raw$List{} + err = c.GetClient().Get(). + $if .namespaced$Namespace(c.GetNamespace()).$end$ + Resource("$.type|resource$"). + Name($.type|private$Name). + SubResource("$.subresourcePath$"). + VersionedParams(&opts, $.schemeParameterCodec|raw$). + Timeout(timeout). + Do(ctx). + Into(result) + return +} +` + +var getTemplate = ` +// Get takes name of the $.type|private$, and returns the corresponding $.resultType|private$ object, and an error if there is any. +func (c *$.type|privatePlural$) Get(ctx $.context|raw$, name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} + err = c.GetClient().Get(). + $if .namespaced$Namespace(c.GetNamespace()).$end$ + Resource("$.type|resource$"). + Name(name). + VersionedParams(&options, $.schemeParameterCodec|raw$). + Do(ctx). + Into(result) + return +} +` + +var getSubresourceTemplate = ` +// Get takes name of the $.type|private$, and returns the corresponding $.resultType|raw$ object, and an error if there is any. +func (c *$.type|privatePlural$) Get(ctx $.context|raw$, $.type|private$Name string, options $.GetOptions|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} + err = c.GetClient().Get(). + $if .namespaced$Namespace(c.GetNamespace()).$end$ + Resource("$.type|resource$"). + Name($.type|private$Name). + SubResource("$.subresourcePath$"). + VersionedParams(&options, $.schemeParameterCodec|raw$). + Do(ctx). + Into(result) + return +} +` + +var deleteTemplate = ` +// Delete takes name of the $.type|private$ and deletes it. Returns an error if one occurs. +func (c *$.type|privatePlural$) Delete(ctx $.context|raw$, name string, opts $.DeleteOptions|raw$) error { + return c.GetClient().Delete(). + $if .namespaced$Namespace(c.GetNamespace()).$end$ + Resource("$.type|resource$"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} +` + +var createSubresourceTemplate = ` +// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *$.type|privatePlural$) Create(ctx $.context|raw$, $.type|private$Name string, $.inputType|private$ *$.inputType|raw$, opts $.CreateOptions|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} + err = c.GetClient().Post(). + $if .namespaced$Namespace(c.GetNamespace()).$end$ + Resource("$.type|resource$"). + Name($.type|private$Name). + SubResource("$.subresourcePath$"). + VersionedParams(&opts, $.schemeParameterCodec|raw$). + Body($.inputType|private$). + Do(ctx). + Into(result) + return +} +` + +var createTemplate = ` +// Create takes the representation of a $.inputType|private$ and creates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *$.type|privatePlural$) Create(ctx $.context|raw$, $.inputType|private$ *$.inputType|raw$, opts $.CreateOptions|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} + err = c.GetClient().Post(). + $if .namespaced$Namespace(c.GetNamespace()).$end$ + Resource("$.type|resource$"). + VersionedParams(&opts, $.schemeParameterCodec|raw$). + Body($.inputType|private$). + Do(ctx). + Into(result) + return +} +` + +var updateSubresourceTemplate = ` +// Update takes the top resource name and the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *$.type|privatePlural$) Update(ctx $.context|raw$, $.type|private$Name string, $.inputType|private$ *$.inputType|raw$, opts $.UpdateOptions|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} + err = c.GetClient().Put(). + $if .namespaced$Namespace(c.GetNamespace()).$end$ + Resource("$.type|resource$"). + Name($.type|private$Name). + SubResource("$.subresourcePath$"). + VersionedParams(&opts, $.schemeParameterCodec|raw$). + Body($.inputType|private$). + Do(ctx). + Into(result) + return +} +` + +var updateTemplate = ` +// Update takes the representation of a $.inputType|private$ and updates it. Returns the server's representation of the $.resultType|private$, and an error, if there is any. +func (c *$.type|privatePlural$) Update(ctx $.context|raw$, $.inputType|private$ *$.inputType|raw$, opts $.UpdateOptions|raw$) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} + err = c.GetClient().Put(). + $if .namespaced$Namespace(c.GetNamespace()).$end$ + Resource("$.type|resource$"). + Name($.inputType|private$.Name). + VersionedParams(&opts, $.schemeParameterCodec|raw$). + Body($.inputType|private$). + Do(ctx). + Into(result) + return +} +` + +var watchTemplate = ` +// Watch returns a $.watchInterface|raw$ that watches the requested $.type|privatePlural$. +func (c *$.type|privatePlural$) Watch(ctx $.context|raw$, opts $.ListOptions|raw$) ($.watchInterface|raw$, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil{ + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.GetClient().Get(). + $if .namespaced$Namespace(c.GetNamespace()).$end$ + VersionedParams(&opts, $.schemeParameterCodec|raw$). + Timeout(timeout). + Watch(ctx) +} +` + +var watchListTemplate = ` +// watchList establishes a watch stream with the server and returns the list of $.resultType|publicPlural$ +func (c *$.type|privatePlural$) watchList(ctx $.context|raw$, opts $.ListOptions|raw$) (result *$.resultType|raw$List, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil{ + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &$.resultType|raw$List{} + err = c.client.Get(). + $if .namespaced$Namespace(c.ns).$end$ + Resource("$.type|resource$"). + VersionedParams(&opts, $.schemeParameterCodec|raw$). + Timeout(timeout). + WatchList(ctx). + Into(result) + return +} +` + +var patchTemplate = ` +// Patch applies the patch and returns the patched $.resultType|private$. +func (c *$.type|privatePlural$) Patch(ctx $.context|raw$, name string, pt $.PatchType|raw$, data []byte, opts $.PatchOptions|raw$, subresources ...string) (result *$.resultType|raw$, err error) { + result = &$.resultType|raw${} + err = c.GetClient().Patch(pt). + $if .namespaced$Namespace(c.GetNamespace()).$end$ + Resource("$.type|resource$"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, $.schemeParameterCodec|raw$). + Body(data). + Do(ctx). + Into(result) + return +} +` + +var applyTemplate = ` +// Apply takes the given apply declarative configuration, applies it and returns the applied $.resultType|private$. +func (c *$.type|privatePlural$) Apply(ctx $.context|raw$, $.inputType|private$ *$.inputApplyConfig|raw$, opts $.ApplyOptions|raw$) (result *$.resultType|raw$, err error) { + if $.inputType|private$ == nil { + return nil, $.fmtErrorf|raw$("$.inputType|private$ provided to Apply must not be nil") + } + patchOpts := opts.ToPatchOptions() + data, err := $.jsonMarshal|raw$($.inputType|private$) + if err != nil { + return nil, err + } + name := $.inputType|private$.Name + if name == nil { + return nil, $.fmtErrorf|raw$("$.inputType|private$.Name must be provided to Apply") + } + result = &$.resultType|raw${} + err = c.GetClient().Patch($.ApplyPatchType|raw$). + $if .namespaced$Namespace(c.GetNamespace()).$end$ + Resource("$.type|resource$"). + Name(*name). + VersionedParams(&patchOpts, $.schemeParameterCodec|raw$). + Body(data). + Do(ctx). + Into(result) + return +} +` + +var applySubresourceTemplate = ` +// Apply takes top resource name and the apply declarative configuration for $.subresourcePath$, +// applies it and returns the applied $.resultType|private$, and an error, if there is any. +func (c *$.type|privatePlural$) Apply(ctx $.context|raw$, $.type|private$Name string, $.inputType|private$ *$.inputApplyConfig|raw$, opts $.ApplyOptions|raw$) (result *$.resultType|raw$, err error) { + if $.inputType|private$ == nil { + return nil, $.fmtErrorf|raw$("$.inputType|private$ provided to Apply must not be nil") + } + patchOpts := opts.ToPatchOptions() + data, err := $.jsonMarshal|raw$($.inputType|private$) + if err != nil { + return nil, err + } + + result = &$.resultType|raw${} + err = c.GetClient().Patch($.ApplyPatchType|raw$). + $if .namespaced$Namespace(c.GetNamespace()).$end$ + Resource("$.type|resource$"). + Name($.type|private$Name). + SubResource("$.subresourcePath$"). + VersionedParams(&patchOpts, $.schemeParameterCodec|raw$). + Body(data). + Do(ctx). + Into(result) + return +} +` diff --git a/code-generator/cmd/client-gen/generators/scheme/generator_for_scheme.go b/code-generator/cmd/client-gen/generators/scheme/generator_for_scheme.go new file mode 100644 index 000000000..722905579 --- /dev/null +++ b/code-generator/cmd/client-gen/generators/scheme/generator_for_scheme.go @@ -0,0 +1,187 @@ +/* +Copyright 2017 The Kubernetes 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 scheme + +import ( + "fmt" + "io" + "os" + "path" + "path/filepath" + "strings" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" +) + +// GenScheme produces a package for a clientset with the scheme, codecs and parameter codecs. +type GenScheme struct { + generator.GoGenerator + OutputPkg string // Must be a Go import-path + OutputPath string // optional + Groups []clientgentypes.GroupVersions + GroupGoNames map[clientgentypes.GroupVersion]string + InputPackages map[clientgentypes.GroupVersion]string + ImportTracker namer.ImportTracker + PrivateScheme bool + CreateRegistry bool + schemeGenerated bool +} + +func (g *GenScheme) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.OutputPkg, g.ImportTracker), + } +} + +// We only want to call GenerateType() once. +func (g *GenScheme) Filter(c *generator.Context, t *types.Type) bool { + ret := !g.schemeGenerated + g.schemeGenerated = true + return ret +} + +func (g *GenScheme) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.ImportTracker.ImportLines()...) + for _, group := range g.Groups { + for _, version := range group.Versions { + packagePath := g.InputPackages[clientgentypes.GroupVersion{Group: group.Group, Version: version.Version}] + groupAlias := strings.ToLower(g.GroupGoNames[clientgentypes.GroupVersion{Group: group.Group, Version: version.Version}]) + if g.CreateRegistry { + // import the install package for internal clientsets instead of the type package with register.go + if version.Version != "" { + packagePath = path.Dir(packagePath) + } + packagePath = path.Join(packagePath, "install") + + imports = append(imports, fmt.Sprintf("%s \"%s\"", groupAlias, packagePath)) + break + } else { + imports = append(imports, fmt.Sprintf("%s%s \"%s\"", groupAlias, strings.ToLower(version.Version.NonEmpty()), packagePath)) + } + } + } + return +} + +func (g *GenScheme) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + + allGroupVersions := clientgentypes.ToGroupVersionInfo(g.Groups, g.GroupGoNames) + allInstallGroups := clientgentypes.ToGroupInstallPackages(g.Groups, g.GroupGoNames) + + m := map[string]interface{}{ + "publicScheme": !g.PrivateScheme, + "allGroupVersions": allGroupVersions, + "allInstallGroups": allInstallGroups, + "customRegister": false, + "runtimeNewParameterCodec": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "NewParameterCodec"}), + "runtimeNewScheme": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "NewScheme"}), + "serializerNewCodecFactory": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/serializer", Name: "NewCodecFactory"}), + "runtimeScheme": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "Scheme"}), + "runtimeSchemeBuilder": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "SchemeBuilder"}), + "runtimeUtilMust": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/util/runtime", Name: "Must"}), + "schemaGroupVersion": c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersion"}), + "metav1AddToGroupVersion": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "AddToGroupVersion"}), + } + globals := map[string]string{ + "Scheme": "Scheme", + "Codecs": "Codecs", + "ParameterCodec": "ParameterCodec", + "Registry": "Registry", + } + for k, v := range globals { + if g.PrivateScheme { + m[k] = strings.ToLower(v[0:1]) + v[1:] + } else { + m[k] = v + } + } + + sw.Do(globalsTemplate, m) + + if g.OutputPath != "" { + if _, err := os.Stat(filepath.Join(g.OutputPath, strings.ToLower("register_custom.go"))); err == nil { + m["customRegister"] = true + } + } + + if g.CreateRegistry { + sw.Do(registryRegistration, m) + } else { + sw.Do(simpleRegistration, m) + } + + return sw.Error() +} + +var globalsTemplate = ` +var $.Scheme$ = $.runtimeNewScheme|raw$() +var $.Codecs$ = $.serializerNewCodecFactory|raw$($.Scheme$) +$if .publicScheme$var $.ParameterCodec$ = $.runtimeNewParameterCodec|raw$($.Scheme$)$end -$` + +var registryRegistration = ` + +func init() { + $.metav1AddToGroupVersion|raw$($.Scheme$, $.schemaGroupVersion|raw${Version: "v1"}) + Install($.Scheme$) +} + +// Install registers the API group and adds types to a scheme +func Install(scheme *$.runtimeScheme|raw$) { + $- range .allInstallGroups$ + $.InstallPackageAlias$.Install(scheme) + $- end$ + $if .customRegister$ + ExtraInstall(scheme) + $end -$ +} +` + +var simpleRegistration = ` +var localSchemeBuilder = $.runtimeSchemeBuilder|raw${ + $- range .allGroupVersions$ + $.PackageAlias$.AddToScheme, + $- end$ + $if .customRegister$ + ExtraAddToScheme, + $end -$ +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + $.metav1AddToGroupVersion|raw$($.Scheme$, $.schemaGroupVersion|raw${Version: "v1"}) + $.runtimeUtilMust|raw$(AddToScheme($.Scheme$)) +} +` diff --git a/code-generator/cmd/client-gen/generators/util/gvpackages.go b/code-generator/cmd/client-gen/generators/util/gvpackages.go new file mode 100644 index 000000000..fcc195090 --- /dev/null +++ b/code-generator/cmd/client-gen/generators/util/gvpackages.go @@ -0,0 +1,30 @@ +/* +Copyright 2021 The Kubernetes 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 util + +import "strings" + +func ParsePathGroupVersion(pgvString string) (gvPath string, gvString string) { + subs := strings.Split(pgvString, "/") + length := len(subs) + switch length { + case 0, 1, 2: + return "", pgvString + default: + return strings.Join(subs[:length-2], "/"), strings.Join(subs[length-2:], "/") + } +} diff --git a/code-generator/cmd/client-gen/generators/util/tags.go b/code-generator/cmd/client-gen/generators/util/tags.go new file mode 100644 index 000000000..5218dfad3 --- /dev/null +++ b/code-generator/cmd/client-gen/generators/util/tags.go @@ -0,0 +1,344 @@ +/* +Copyright 2016 The Kubernetes 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 util + +import ( + "errors" + "fmt" + "strings" + + "k8s.io/gengo/v2" +) + +var supportedTags = []string{ + "genclient", + "genclient:nonNamespaced", + "genclient:noVerbs", + "genclient:onlyVerbs", + "genclient:skipVerbs", + "genclient:noStatus", + "genclient:readonly", + "genclient:method", +} + +// SupportedVerbs is a list of supported verbs for +onlyVerbs and +skipVerbs. +var SupportedVerbs = []string{ + "create", + "update", + "updateStatus", + "delete", + "deleteCollection", + "get", + "list", + "watch", + "patch", + "apply", + "applyStatus", +} + +// ReadonlyVerbs represents a list of read-only verbs. +var ReadonlyVerbs = []string{ + "get", + "list", + "watch", +} + +// genClientPrefix is the default prefix for all genclient tags. +const genClientPrefix = "genclient:" + +// unsupportedExtensionVerbs is a list of verbs we don't support generating +// extension client functions for. +var unsupportedExtensionVerbs = []string{ + "updateStatus", + "deleteCollection", + "watch", + "delete", +} + +// inputTypeSupportedVerbs is a list of verb types that supports overriding the +// input argument type. +var inputTypeSupportedVerbs = []string{ + "create", + "update", + "apply", +} + +// resultTypeSupportedVerbs is a list of verb types that supports overriding the +// resulting type. +var resultTypeSupportedVerbs = []string{ + "create", + "update", + "get", + "list", + "patch", + "apply", +} + +// Extensions allows to extend the default set of client verbs +// (CRUD+watch+patch+list+deleteCollection) for a given type with custom defined +// verbs. Custom verbs can have custom input and result types and also allow to +// use a sub-resource in a request instead of top-level resource type. +// +// Example: +// +// +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale +// +// type ReplicaSet struct { ... } +// +// The 'method=UpdateScale' is the name of the client function. +// The 'verb=update' here means the client function will use 'PUT' action. +// The 'subresource=scale' means we will use SubResource template to generate this client function. +// The 'input' is the input type used for creation (function argument). +// The 'result' (not needed in this case) is the result type returned from the +// client function. +type extension struct { + // VerbName is the name of the custom verb (Scale, Instantiate, etc..) + VerbName string + // VerbType is the type of the verb (only verbs from SupportedVerbs are + // supported) + VerbType string + // SubResourcePath defines a path to a sub-resource to use in the request. + // (optional) + SubResourcePath string + // InputTypeOverride overrides the input parameter type for the verb. By + // default the original type is used. Overriding the input type only works for + // "create" and "update" verb types. The given type must exists in the same + // package as the original type. + // (optional) + InputTypeOverride string + // ResultTypeOverride overrides the resulting object type for the verb. By + // default the original type is used. Overriding the result type works. + // (optional) + ResultTypeOverride string +} + +// IsSubresource indicates if this extension should generate the sub-resource. +func (e *extension) IsSubresource() bool { + return len(e.SubResourcePath) > 0 +} + +// HasVerb checks if the extension matches the given verb. +func (e *extension) HasVerb(verb string) bool { + return e.VerbType == verb +} + +// Input returns the input override package path and the type. +func (e *extension) Input() (string, string) { + parts := strings.Split(e.InputTypeOverride, ".") + return parts[len(parts)-1], strings.Join(parts[0:len(parts)-1], ".") +} + +// Result returns the result override package path and the type. +func (e *extension) Result() (string, string) { + parts := strings.Split(e.ResultTypeOverride, ".") + return parts[len(parts)-1], strings.Join(parts[0:len(parts)-1], ".") +} + +// Tags represents a genclient configuration for a single type. +type Tags struct { + // +genclient + GenerateClient bool + // +genclient:nonNamespaced + NonNamespaced bool + // +genclient:noStatus + NoStatus bool + // +genclient:noVerbs + NoVerbs bool + // +genclient:skipVerbs=get,update + // +genclient:onlyVerbs=create,delete + SkipVerbs []string + // +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale + Extensions []extension +} + +// HasVerb returns true if we should include the given verb in final client interface and +// generate the function for it. +func (t Tags) HasVerb(verb string) bool { + if len(t.SkipVerbs) == 0 { + return true + } + for _, s := range t.SkipVerbs { + if verb == s { + return false + } + } + return true +} + +// MustParseClientGenTags calls ParseClientGenTags but instead of returning error it panics. +func MustParseClientGenTags(lines []string) Tags { + tags, err := ParseClientGenTags(lines) + if err != nil { + panic(err.Error()) + } + return tags +} + +// ParseClientGenTags parse the provided genclient tags and validates that no unknown +// tags are provided. +func ParseClientGenTags(lines []string) (Tags, error) { + ret := Tags{} + values := gengo.ExtractCommentTags("+", lines) + var value []string + value, ret.GenerateClient = values["genclient"] + // Check the old format and error when used to avoid generating client when //+genclient=false + if len(value) > 0 && len(value[0]) > 0 { + return ret, fmt.Errorf("+genclient=%s is invalid, use //+genclient if you want to generate client or omit it when you want to disable generation", value) + } + _, ret.NonNamespaced = values[genClientPrefix+"nonNamespaced"] + // Check the old format and error when used + if value := values["nonNamespaced"]; len(value) > 0 && len(value[0]) > 0 { + return ret, fmt.Errorf("+nonNamespaced=%s is invalid, use //+genclient:nonNamespaced instead", value[0]) + } + _, ret.NoVerbs = values[genClientPrefix+"noVerbs"] + _, ret.NoStatus = values[genClientPrefix+"noStatus"] + onlyVerbs := []string{} + if _, isReadonly := values[genClientPrefix+"readonly"]; isReadonly { + onlyVerbs = ReadonlyVerbs + } + // Check the old format and error when used + if value := values["readonly"]; len(value) > 0 && len(value[0]) > 0 { + return ret, fmt.Errorf("+readonly=%s is invalid, use //+genclient:readonly instead", value[0]) + } + if v, exists := values[genClientPrefix+"skipVerbs"]; exists { + ret.SkipVerbs = strings.Split(v[0], ",") + } + if v, exists := values[genClientPrefix+"onlyVerbs"]; exists || len(onlyVerbs) > 0 { + if len(v) > 0 { + onlyVerbs = append(onlyVerbs, strings.Split(v[0], ",")...) + } + skipVerbs := []string{} + for _, m := range SupportedVerbs { + skip := true + for _, o := range onlyVerbs { + if o == m { + skip = false + break + } + } + // Check for conflicts + for _, v := range skipVerbs { + if v == m { + return ret, fmt.Errorf("verb %q used both in genclient:skipVerbs and genclient:onlyVerbs", v) + } + } + if skip { + skipVerbs = append(skipVerbs, m) + } + } + ret.SkipVerbs = skipVerbs + } + var err error + if ret.Extensions, err = parseClientExtensions(values); err != nil { + return ret, err + } + return ret, validateClientGenTags(values) +} + +func parseClientExtensions(tags map[string][]string) ([]extension, error) { + var ret []extension + for name, values := range tags { + if !strings.HasPrefix(name, genClientPrefix+"method") { + continue + } + for _, value := range values { + // the value comes in this form: "Foo,verb=create" + ext := extension{} + parts := strings.Split(value, ",") + if len(parts) == 0 { + return nil, fmt.Errorf("invalid of empty extension verb name: %q", value) + } + // The first part represents the name of the extension + ext.VerbName = parts[0] + if len(ext.VerbName) == 0 { + return nil, fmt.Errorf("must specify a verb name (// +genclient:method=Foo,verb=create)") + } + // Parse rest of the arguments + params := parts[1:] + for _, p := range params { + parts := strings.Split(p, "=") + if len(parts) != 2 { + return nil, fmt.Errorf("invalid extension tag specification %q", p) + } + key, val := strings.TrimSpace(parts[0]), strings.TrimSpace(parts[1]) + if len(val) == 0 { + return nil, fmt.Errorf("empty value of %q for %q extension", key, ext.VerbName) + } + switch key { + case "verb": + ext.VerbType = val + case "subresource": + ext.SubResourcePath = val + case "input": + ext.InputTypeOverride = val + case "result": + ext.ResultTypeOverride = val + default: + return nil, fmt.Errorf("unknown extension configuration key %q", key) + } + } + // Validate resulting extension configuration + if len(ext.VerbType) == 0 { + return nil, fmt.Errorf("verb type must be specified (use '// +genclient:method=%s,verb=create')", ext.VerbName) + } + if len(ext.ResultTypeOverride) > 0 { + supported := false + for _, v := range resultTypeSupportedVerbs { + if ext.VerbType == v { + supported = true + break + } + } + if !supported { + return nil, fmt.Errorf("%s: result type is not supported for %q verbs (supported verbs: %#v)", ext.VerbName, ext.VerbType, resultTypeSupportedVerbs) + } + } + if len(ext.InputTypeOverride) > 0 { + supported := false + for _, v := range inputTypeSupportedVerbs { + if ext.VerbType == v { + supported = true + break + } + } + if !supported { + return nil, fmt.Errorf("%s: input type is not supported for %q verbs (supported verbs: %#v)", ext.VerbName, ext.VerbType, inputTypeSupportedVerbs) + } + } + for _, t := range unsupportedExtensionVerbs { + if ext.VerbType == t { + return nil, fmt.Errorf("verb %q is not supported by extension generator", ext.VerbType) + } + } + ret = append(ret, ext) + } + } + return ret, nil +} + +// validateTags validates that only supported genclient tags were provided. +func validateClientGenTags(values map[string][]string) error { + for _, k := range supportedTags { + delete(values, k) + } + for key := range values { + if strings.HasPrefix(key, strings.TrimSuffix(genClientPrefix, ":")) { + return errors.New("unknown tag detected: " + key) + } + } + return nil +} diff --git a/code-generator/cmd/client-gen/generators/util/tags_test.go b/code-generator/cmd/client-gen/generators/util/tags_test.go new file mode 100644 index 000000000..b9ffcfbbb --- /dev/null +++ b/code-generator/cmd/client-gen/generators/util/tags_test.go @@ -0,0 +1,148 @@ +/* +Copyright 2016 The Kubernetes 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 util + +import ( + "reflect" + "testing" +) + +func TestParseTags(t *testing.T) { + testCases := map[string]struct { + lines []string + expectTags Tags + expectError bool + }{ + "genclient": { + lines: []string{`+genclient`}, + expectTags: Tags{GenerateClient: true}, + }, + "genclient=true": { + lines: []string{`+genclient=true`}, + expectError: true, + }, + "nonNamespaced=true": { + lines: []string{`+genclient=true`, `+nonNamespaced=true`}, + expectError: true, + }, + "readonly=true": { + lines: []string{`+genclient=true`, `+readonly=true`}, + expectError: true, + }, + "genclient:nonNamespaced": { + lines: []string{`+genclient`, `+genclient:nonNamespaced`}, + expectTags: Tags{GenerateClient: true, NonNamespaced: true}, + }, + "genclient:noVerbs": { + lines: []string{`+genclient`, `+genclient:noVerbs`}, + expectTags: Tags{GenerateClient: true, NoVerbs: true}, + }, + "genclient:noStatus": { + lines: []string{`+genclient`, `+genclient:noStatus`}, + expectTags: Tags{GenerateClient: true, NoStatus: true}, + }, + "genclient:onlyVerbs": { + lines: []string{`+genclient`, `+genclient:onlyVerbs=create,delete`}, + expectTags: Tags{GenerateClient: true, SkipVerbs: []string{"update", "updateStatus", "deleteCollection", "get", "list", "watch", "patch", "apply", "applyStatus"}}, + }, + "genclient:readonly": { + lines: []string{`+genclient`, `+genclient:readonly`}, + expectTags: Tags{GenerateClient: true, SkipVerbs: []string{"create", "update", "updateStatus", "delete", "deleteCollection", "patch", "apply", "applyStatus"}}, + }, + "genclient:conflict": { + lines: []string{`+genclient`, `+genclient:onlyVerbs=create`, `+genclient:skipVerbs=create`}, + expectError: true, + }, + "genclient:invalid": { + lines: []string{`+genclient`, `+genclient:invalid`}, + expectError: true, + }, + } + for key, c := range testCases { + result, err := ParseClientGenTags(c.lines) + if err != nil && !c.expectError { + t.Fatalf("unexpected error: %v", err) + } + if !c.expectError && !reflect.DeepEqual(result, c.expectTags) { + t.Errorf("[%s] expected %#v to be %#v", key, result, c.expectTags) + } + } +} + +func TestParseTagsExtension(t *testing.T) { + testCases := map[string]struct { + lines []string + expectedExtensions []extension + expectError bool + }{ + "simplest extension": { + lines: []string{`+genclient:method=Foo,verb=create`}, + expectedExtensions: []extension{{VerbName: "Foo", VerbType: "create"}}, + }, + "multiple extensions": { + lines: []string{`+genclient:method=Foo,verb=create`, `+genclient:method=Bar,verb=get`}, + expectedExtensions: []extension{{VerbName: "Foo", VerbType: "create"}, {VerbName: "Bar", VerbType: "get"}}, + }, + "extension without verb": { + lines: []string{`+genclient:method`}, + expectError: true, + }, + "extension without verb type": { + lines: []string{`+genclient:method=Foo`}, + expectError: true, + }, + "sub-resource extension": { + lines: []string{`+genclient:method=Foo,verb=create,subresource=bar`}, + expectedExtensions: []extension{{VerbName: "Foo", VerbType: "create", SubResourcePath: "bar"}}, + }, + "output type extension": { + lines: []string{`+genclient:method=Foos,verb=list,result=Bars`}, + expectedExtensions: []extension{{VerbName: "Foos", VerbType: "list", ResultTypeOverride: "Bars"}}, + }, + "input type extension": { + lines: []string{`+genclient:method=Foo,verb=update,input=Bar`}, + expectedExtensions: []extension{{VerbName: "Foo", VerbType: "update", InputTypeOverride: "Bar"}}, + }, + "unknown verb type extension": { + lines: []string{`+genclient:method=Foo,verb=explode`}, + expectedExtensions: nil, + expectError: true, + }, + "invalid verb extension": { + lines: []string{`+genclient:method=Foo,unknown=bar`}, + expectedExtensions: nil, + expectError: true, + }, + "empty verb extension subresource": { + lines: []string{`+genclient:method=Foo,verb=get,subresource=`}, + expectedExtensions: nil, + expectError: true, + }, + } + for key, c := range testCases { + result, err := ParseClientGenTags(c.lines) + if err != nil && !c.expectError { + t.Fatalf("[%s] unexpected error: %v", key, err) + } + if err != nil && c.expectError { + t.Logf("[%s] got expected error: %+v", key, err) + } + if !c.expectError && !reflect.DeepEqual(result.Extensions, c.expectedExtensions) { + t.Errorf("[%s] expected %#+v to be %#+v", key, result.Extensions, c.expectedExtensions) + } + } +} diff --git a/code-generator/cmd/client-gen/main.go b/code-generator/cmd/client-gen/main.go new file mode 100644 index 000000000..09866e93c --- /dev/null +++ b/code-generator/cmd/client-gen/main.go @@ -0,0 +1,67 @@ +/* +Copyright 2015 The Kubernetes 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. +*/ + +// client-gen makes the individual typed clients using gengo. +package main + +import ( + "flag" + + "github.com/spf13/pflag" + "k8s.io/klog/v2" + + "k8s.io/code-generator/cmd/client-gen/args" + "k8s.io/code-generator/cmd/client-gen/generators" + "k8s.io/code-generator/pkg/util" + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" +) + +func main() { + klog.InitFlags(nil) + args := args.New() + + args.AddFlags(pflag.CommandLine, "k8s.io/kubernetes/pkg/apis") // TODO: move this input path out of client-gen + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + // add group version package as input dirs for gengo + inputPkgs := []string{} + for _, pkg := range args.Groups { + for _, v := range pkg.Versions { + inputPkgs = append(inputPkgs, v.Package) + } + } + + if err := args.Validate(); err != nil { + klog.Fatalf("Error: %v", err) + } + + myTargets := func(context *generator.Context) []generator.Target { + return generators.GetTargets(context, args) + } + + if err := gengo.Execute( + generators.NameSystems(util.PluralExceptionListToMapOrDie(args.PluralExceptions)), + generators.DefaultNameSystem(), + myTargets, + gengo.StdBuildTag, + inputPkgs, + ); err != nil { + klog.Fatalf("Error: %v", err) + } +} diff --git a/code-generator/cmd/client-gen/types/helpers.go b/code-generator/cmd/client-gen/types/helpers.go new file mode 100644 index 000000000..c84a77531 --- /dev/null +++ b/code-generator/cmd/client-gen/types/helpers.go @@ -0,0 +1,121 @@ +/* +Copyright 2016 The Kubernetes 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 types + +import ( + "fmt" + "regexp" + "sort" + "strings" + + "k8s.io/gengo/v2/namer" +) + +// ToGroupVersion turns "group/version" string into a GroupVersion struct. It reports error +// if it cannot parse the string. +func ToGroupVersion(gv string) (GroupVersion, error) { + // this can be the internal version for the legacy kube types + // TODO once we've cleared the last uses as strings, this special case should be removed. + if (len(gv) == 0) || (gv == "/") { + return GroupVersion{}, nil + } + + switch strings.Count(gv, "/") { + case 0: + return GroupVersion{Group(gv), ""}, nil + case 1: + i := strings.Index(gv, "/") + return GroupVersion{Group(gv[:i]), Version(gv[i+1:])}, nil + default: + return GroupVersion{}, fmt.Errorf("unexpected GroupVersion string: %v", gv) + } +} + +type sortableSliceOfVersions []string + +func (a sortableSliceOfVersions) Len() int { return len(a) } +func (a sortableSliceOfVersions) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a sortableSliceOfVersions) Less(i, j int) bool { + vi, vj := strings.TrimLeft(a[i], "v"), strings.TrimLeft(a[j], "v") + major := regexp.MustCompile("^[0-9]+") + viMajor, vjMajor := major.FindString(vi), major.FindString(vj) + viRemaining, vjRemaining := strings.TrimLeft(vi, viMajor), strings.TrimLeft(vj, vjMajor) + switch { + case len(viRemaining) == 0 && len(vjRemaining) == 0: + return viMajor < vjMajor + case len(viRemaining) == 0 && len(vjRemaining) != 0: + // stable version is greater than unstable version + return false + case len(viRemaining) != 0 && len(vjRemaining) == 0: + // stable version is greater than unstable version + return true + } + // neither are stable versions + if viMajor != vjMajor { + return viMajor < vjMajor + } + // assuming at most we have one alpha or one beta version, so if vi contains "alpha", it's the lesser one. + return strings.Contains(viRemaining, "alpha") +} + +// Determine the default version among versions. If a user calls a group client +// without specifying the version (e.g., c.CoreV1(), instead of c.CoreV1()), the +// default version will be returned. +func defaultVersion(versions []PackageVersion) Version { + var versionStrings []string + for _, version := range versions { + versionStrings = append(versionStrings, version.Version.String()) + } + sort.Sort(sortableSliceOfVersions(versionStrings)) + return Version(versionStrings[len(versionStrings)-1]) +} + +// ToGroupVersionInfo is a helper function used by generators for groups. +func ToGroupVersionInfo(groups []GroupVersions, groupGoNames map[GroupVersion]string) []GroupVersionInfo { + var groupVersionPackages []GroupVersionInfo + for _, group := range groups { + for _, version := range group.Versions { + groupGoName := groupGoNames[GroupVersion{Group: group.Group, Version: version.Version}] + groupVersionPackages = append(groupVersionPackages, GroupVersionInfo{ + Group: Group(namer.IC(group.Group.NonEmpty())), + Version: Version(namer.IC(version.Version.String())), + PackageAlias: strings.ToLower(groupGoName + version.Version.NonEmpty()), + GroupGoName: groupGoName, + LowerCaseGroupGoName: namer.IL(groupGoName), + }) + } + } + return groupVersionPackages +} + +func ToGroupInstallPackages(groups []GroupVersions, groupGoNames map[GroupVersion]string) []GroupInstallPackage { + var groupInstallPackages []GroupInstallPackage + for _, group := range groups { + defaultVersion := defaultVersion(group.Versions) + groupGoName := groupGoNames[GroupVersion{Group: group.Group, Version: defaultVersion}] + groupInstallPackages = append(groupInstallPackages, GroupInstallPackage{ + Group: Group(namer.IC(group.Group.NonEmpty())), + InstallPackageAlias: strings.ToLower(groupGoName), + }) + } + return groupInstallPackages +} + +// NormalizeGroupVersion calls normalizes the GroupVersion. +// func NormalizeGroupVersion(gv GroupVersion) GroupVersion { +// return GroupVersion{Group: gv.Group.NonEmpty(), Version: gv.Version, NonEmptyVersion: normalization.Version(gv.Version)} +// } diff --git a/code-generator/cmd/client-gen/types/helpers_test.go b/code-generator/cmd/client-gen/types/helpers_test.go new file mode 100644 index 000000000..dec62dff2 --- /dev/null +++ b/code-generator/cmd/client-gen/types/helpers_test.go @@ -0,0 +1,32 @@ +/* +Copyright 2016 The Kubernetes 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 types + +import ( + "reflect" + "sort" + "testing" +) + +func TestVersionSort(t *testing.T) { + unsortedVersions := []string{"v4beta1", "v2beta1", "v2alpha1", "v3", "v1"} + expected := []string{"v2alpha1", "v2beta1", "v4beta1", "v1", "v3"} + sort.Sort(sortableSliceOfVersions(unsortedVersions)) + if !reflect.DeepEqual(unsortedVersions, expected) { + t.Errorf("expected %#v\ngot %#v", expected, unsortedVersions) + } +} diff --git a/code-generator/cmd/client-gen/types/types.go b/code-generator/cmd/client-gen/types/types.go new file mode 100644 index 000000000..df030e845 --- /dev/null +++ b/code-generator/cmd/client-gen/types/types.go @@ -0,0 +1,109 @@ +/* +Copyright 2016 The Kubernetes 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 types + +import "strings" + +type Version string + +func (v Version) String() string { + return string(v) +} + +func (v Version) NonEmpty() string { + if v == "" { + return "internalVersion" + } + return v.String() +} + +func (v Version) PackageName() string { + return strings.ToLower(v.NonEmpty()) +} + +type Group string + +func (g Group) String() string { + return string(g) +} + +func (g Group) NonEmpty() string { + if g == "" { + return "core" + } + return string(g) +} + +func (g Group) PackageName() string { + parts := strings.Split(g.NonEmpty(), ".") + if parts[0] == "internal" && len(parts) > 1 { + return strings.ToLower(parts[1] + parts[0]) + } + return strings.ToLower(parts[0]) +} + +type Kind string + +type PackageVersion struct { + Version + // The fully qualified package, e.g. k8s.io/kubernetes/pkg/apis/apps, where the types.go is found. + Package string +} + +type GroupVersion struct { + Group Group + Version Version +} + +type GroupVersionKind struct { + Group Group + Version Version + Kind Kind +} + +func (gv GroupVersion) ToAPIVersion() string { + if len(gv.Group) > 0 && gv.Group != "" { + return gv.Group.String() + "/" + gv.Version.String() + } else { + return gv.Version.String() + } +} + +func (gv GroupVersion) WithKind(kind Kind) GroupVersionKind { + return GroupVersionKind{Group: gv.Group, Version: gv.Version, Kind: kind} +} + +type GroupVersions struct { + // The name of the package for this group, e.g. apps. + PackageName string + Group Group + Versions []PackageVersion +} + +// GroupVersionInfo contains all the info around a group version. +type GroupVersionInfo struct { + Group Group + Version Version + PackageAlias string + GroupGoName string + LowerCaseGroupGoName string +} + +type GroupInstallPackage struct { + Group Group + InstallPackageAlias string +} diff --git a/code-generator/cmd/conversion-gen/args/args.go b/code-generator/cmd/conversion-gen/args/args.go new file mode 100644 index 000000000..cc61c48d4 --- /dev/null +++ b/code-generator/cmd/conversion-gen/args/args.go @@ -0,0 +1,92 @@ +/* +Copyright 2017 The Kubernetes 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" +) + +// DefaultBasePeerDirs are the peer-dirs nearly everybody will use, i.e. those coming from +// apimachinery. +var DefaultBasePeerDirs = []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1", + "k8s.io/apimachinery/pkg/conversion", + "k8s.io/apimachinery/pkg/runtime", +} + +type Args struct { + // The filename of the generated results. + OutputFile string + + // Base peer dirs which nearly everybody will use, i.e. outside of Kubernetes core. Peer dirs + // are declared to make the generator pick up manually written conversion funcs from external + // packages. + BasePeerDirs []string + + // Custom peer dirs which are application specific. Peer dirs are declared to make the + // generator pick up manually written conversion funcs from external packages. + ExtraPeerDirs []string + + // Additional dirs to parse and load, but not consider for peers. This is + // useful when packages depend on other packages and want to call + // conversions across them. + ExtraDirs []string + + // SkipUnsafe indicates whether to generate unsafe conversions to improve the efficiency + // of these operations. The unsafe operation is a direct pointer assignment via unsafe + // (within the allowed uses of unsafe) and is equivalent to a proposed Golang change to + // allow structs that are identical to be assigned to each other. + SkipUnsafe bool + + // GoHeaderFile is the path to a boilerplate header file for generated + // code. + GoHeaderFile string +} + +// New returns default arguments for the generator. +func New() *Args { + return &Args{ + BasePeerDirs: DefaultBasePeerDirs, + SkipUnsafe: false, + } +} + +// AddFlags add the generator flags to the flag set. +func (args *Args) AddFlags(fs *pflag.FlagSet) { + fs.StringVar(&args.OutputFile, "output-file", "generated.conversion.go", + "the name of the file to be generated") + fs.StringSliceVar(&args.BasePeerDirs, "base-peer-dirs", args.BasePeerDirs, + "Comma-separated list of apimachinery import paths which are considered, after tag-specified peers, for conversions. Only change these if you have very good reasons.") + fs.StringSliceVar(&args.ExtraPeerDirs, "extra-peer-dirs", args.ExtraPeerDirs, + "Application specific comma-separated list of import paths which are considered, after tag-specified peers and base-peer-dirs, for conversions.") + fs.StringSliceVar(&args.ExtraDirs, "extra-dirs", args.ExtraDirs, + "Application specific comma-separated list of import paths which are loaded and considered for callable conversions, but are not considered peers for conversion.") + fs.BoolVar(&args.SkipUnsafe, "skip-unsafe", args.SkipUnsafe, + "If true, will not generate code using unsafe pointer conversions; resulting code may be slower.") + fs.StringVar(&args.GoHeaderFile, "go-header-file", "", + "the path to a file containing boilerplate header text; the string \"YEAR\" will be replaced with the current 4-digit year") +} + +// Validate checks the given arguments. +func (args *Args) Validate() error { + if len(args.OutputFile) == 0 { + return fmt.Errorf("--output-file must be specified") + } + return nil +} diff --git a/code-generator/cmd/conversion-gen/generators/conversion.go b/code-generator/cmd/conversion-gen/generators/conversion.go new file mode 100644 index 000000000..b1ac8209a --- /dev/null +++ b/code-generator/cmd/conversion-gen/generators/conversion.go @@ -0,0 +1,1207 @@ +/* +Copyright 2016 The Kubernetes 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 ( + "bytes" + "fmt" + "io" + "path" + "reflect" + "sort" + "strings" + + "k8s.io/code-generator/cmd/conversion-gen/args" + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + "k8s.io/klog/v2" +) + +// These are the comment tags that carry parameters for conversion generation. +const ( + // e.g., "+k8s:conversion-gen=" in doc.go, where is the + // import path of the package the peer types are defined in. + // e.g., "+k8s:conversion-gen=false" in a type's comment will let + // conversion-gen skip that type. + tagName = "k8s:conversion-gen" + // e.g. "+k8s:conversion-gen:explicit-from=net/url.Values" in the type comment + // will result in generating conversion from net/url.Values. + explicitFromTagName = "k8s:conversion-gen:explicit-from" + // e.g., "+k8s:conversion-gen-external-types=" in doc.go, where + // is the relative path to the package the types are defined in. + externalTypesTagName = "k8s:conversion-gen-external-types" +) + +func extractTag(comments []string) []string { + return gengo.ExtractCommentTags("+", comments)[tagName] +} + +func extractExplicitFromTag(comments []string) []string { + return gengo.ExtractCommentTags("+", comments)[explicitFromTagName] +} + +func extractExternalTypesTag(comments []string) []string { + return gengo.ExtractCommentTags("+", comments)[externalTypesTagName] +} + +func isCopyOnly(comments []string) bool { + values := gengo.ExtractCommentTags("+", comments)["k8s:conversion-fn"] + return len(values) == 1 && values[0] == "copy-only" +} + +func isDrop(comments []string) bool { + values := gengo.ExtractCommentTags("+", comments)["k8s:conversion-fn"] + return len(values) == 1 && values[0] == "drop" +} + +// TODO: This is created only to reduce number of changes in a single PR. +// Remove it and use PublicNamer instead. +func conversionNamer() *namer.NameStrategy { + return &namer.NameStrategy{ + Join: func(pre string, in []string, post string) string { + return strings.Join(in, "_") + }, + PrependPackageNames: 1, + } +} + +func defaultFnNamer() *namer.NameStrategy { + return &namer.NameStrategy{ + Prefix: "SetDefaults_", + Join: func(pre string, in []string, post string) string { + return pre + strings.Join(in, "_") + post + }, + } +} + +// NameSystems returns the name system used by the generators in this package. +func NameSystems() namer.NameSystems { + return namer.NameSystems{ + "public": conversionNamer(), + "raw": namer.NewRawNamer("", nil), + "defaultfn": defaultFnNamer(), + } +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +func getPeerTypeFor(context *generator.Context, t *types.Type, potenialPeerPkgs []string) *types.Type { + for _, ppp := range potenialPeerPkgs { + p := context.Universe.Package(ppp) + if p == nil { + continue + } + if p.Has(t.Name.Name) { + return p.Type(t.Name.Name) + } + } + return nil +} + +type conversionPair struct { + inType *types.Type + outType *types.Type +} + +// All of the types in conversions map are of type "DeclarationOf" with +// the underlying type being "Func". +type conversionFuncMap map[conversionPair]*types.Type + +// Returns all manually-defined conversion functions in the package. +func getManualConversionFunctions(context *generator.Context, pkg *types.Package, manualMap conversionFuncMap) { + if pkg == nil { + klog.Warning("Skipping nil package passed to getManualConversionFunctions") + return + } + klog.V(3).Infof("Scanning for conversion functions in %v", pkg.Path) + + scopeName := types.Ref(conversionPackagePath, "Scope").Name + errorName := types.Ref("", "error").Name + buffer := &bytes.Buffer{} + sw := generator.NewSnippetWriter(buffer, context, "$", "$") + + for _, f := range pkg.Functions { + if f.Underlying == nil || f.Underlying.Kind != types.Func { + klog.Errorf("Malformed function: %#v", f) + continue + } + if f.Underlying.Signature == nil { + klog.Errorf("Function without signature: %#v", f) + continue + } + klog.V(6).Infof("Considering function %s", f.Name) + signature := f.Underlying.Signature + // Check whether the function is conversion function. + // Note that all of them have signature: + // func Convert_inType_To_outType(inType, outType, conversion.Scope) error + if signature.Receiver != nil { + klog.V(6).Infof("%s has a receiver", f.Name) + continue + } + if len(signature.Parameters) != 3 || signature.Parameters[2].Type.Name != scopeName { + klog.V(6).Infof("%s has wrong parameters", f.Name) + continue + } + if len(signature.Results) != 1 || signature.Results[0].Type.Name != errorName { + klog.V(6).Infof("%s has wrong results", f.Name) + continue + } + inType := signature.Parameters[0].Type + outType := signature.Parameters[1].Type + if inType.Kind != types.Pointer || outType.Kind != types.Pointer { + klog.V(6).Infof("%s has wrong parameter types", f.Name) + continue + } + // Now check if the name satisfies the convention. + // TODO: This should call the Namer directly. + args := argsFromType(inType.Elem, outType.Elem) + sw.Do("Convert_$.inType|public$_To_$.outType|public$", args) + if f.Name.Name == buffer.String() { + klog.V(2).Infof("Found conversion function %s", f.Name) + key := conversionPair{inType.Elem, outType.Elem} + // We might scan the same package twice, and that's OK. + if v, ok := manualMap[key]; ok && v != nil && v.Name.Package != pkg.Path { + panic(fmt.Sprintf("duplicate static conversion defined: %s -> %s from:\n%s.%s\n%s.%s", key.inType, key.outType, v.Name.Package, v.Name.Name, f.Name.Package, f.Name.Name)) + } + manualMap[key] = f + } else { + // prevent user error when they don't get the correct conversion signature + if strings.HasPrefix(f.Name.Name, "Convert_") { + klog.Errorf("Rename function %s %s -> %s to match expected conversion signature", f.Name.Package, f.Name.Name, buffer.String()) + } + klog.V(3).Infof("%s has wrong name", f.Name) + } + buffer.Reset() + } +} + +func GetTargets(context *generator.Context, args *args.Args) []generator.Target { + boilerplate, err := gengo.GoBoilerplate(args.GoHeaderFile, gengo.StdBuildTag, gengo.StdGeneratedBy) + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + targets := []generator.Target{} + + // Accumulate pre-existing conversion functions. + // TODO: This is too ad-hoc. We need a better way. + manualConversions := conversionFuncMap{} + + // Record types that are memory equivalent. A type is memory equivalent + // if it has the same memory layout and no nested manual conversion is + // defined. + // TODO: in the future, relax the nested manual conversion requirement + // if we can show that a large enough types are memory identical but + // have non-trivial conversion + memoryEquivalentTypes := equalMemoryTypes{} + + // First load other "input" packages. We do this as a single call because + // it is MUCH faster. + filteredInputs := make([]string, 0, len(context.Inputs)) + otherPkgs := make([]string, 0, len(context.Inputs)) + pkgToPeers := map[string][]string{} + pkgToExternal := map[string]string{} + for _, i := range context.Inputs { + klog.V(3).Infof("pre-processing pkg %q", i) + + pkg := context.Universe[i] + + // Only generate conversions for packages which explicitly request it + // by specifying one or more "+k8s:conversion-gen=" + // in their doc.go file. + peerPkgs := extractTag(pkg.Comments) + if peerPkgs == nil { + klog.V(3).Infof(" no tag") + continue + } + klog.V(3).Infof(" tags: %q", peerPkgs) + if len(peerPkgs) == 1 && peerPkgs[0] == "false" { + // If a single +k8s:conversion-gen=false tag is defined, we still want + // the generator to fire for this package for explicit conversions, but + // we are clearing the peerPkgs to not generate any standard conversions. + peerPkgs = nil + } else { + // Save peers for each input + pkgToPeers[i] = peerPkgs + } + otherPkgs = append(otherPkgs, peerPkgs...) + // Keep this one for further processing. + filteredInputs = append(filteredInputs, i) + + // if the external types are not in the same package where the + // conversion functions to be generated + externalTypesValues := extractExternalTypesTag(pkg.Comments) + if externalTypesValues != nil { + if len(externalTypesValues) != 1 { + klog.Fatalf(" expect only one value for %q tag, got: %q", externalTypesTagName, externalTypesValues) + } + externalTypes := externalTypesValues[0] + klog.V(3).Infof(" external types tags: %q", externalTypes) + otherPkgs = append(otherPkgs, externalTypes) + pkgToExternal[i] = externalTypes + } else { + pkgToExternal[i] = i + } + } + + // Make sure explicit peer-packages are added. + peers := args.BasePeerDirs + peers = append(peers, args.ExtraPeerDirs...) + if expanded, err := context.FindPackages(peers...); err != nil { + klog.Fatalf("cannot find peer packages: %v", err) + } else { + otherPkgs = append(otherPkgs, expanded...) + // for each pkg, add these extras, too + for k := range pkgToPeers { + pkgToPeers[k] = append(pkgToPeers[k], expanded...) + } + } + + if len(otherPkgs) > 0 { + if _, err := context.LoadPackages(otherPkgs...); err != nil { + klog.Fatalf("cannot load packages: %v", err) + } + } + // update context.Order to the latest context.Universe + orderer := namer.Orderer{Namer: namer.NewPublicNamer(1)} + context.Order = orderer.OrderUniverse(context.Universe) + + // Look for conversion functions in the peer-packages. + for _, pp := range otherPkgs { + p := context.Universe[pp] + if p == nil { + klog.Fatalf("failed to find pkg: %s", pp) + } + getManualConversionFunctions(context, p, manualConversions) + } + + // We are generating conversions only for packages that are explicitly + // passed as InputDir. + for _, i := range filteredInputs { + klog.V(3).Infof("considering pkg %q", i) + pkg := context.Universe[i] + // typesPkg is where the versioned types are defined. Sometimes it is + // different from pkg. For example, kubernetes core/v1 types are defined + // in k8s.io/api/core/v1, while pkg is at pkg/api/v1. + typesPkg := pkg + + // Add conversion and defaulting functions. + getManualConversionFunctions(context, pkg, manualConversions) + + // Find the right input pkg, which might not be this one. + externalTypes := pkgToExternal[i] + typesPkg = context.Universe[externalTypes] + + unsafeEquality := TypesEqual(memoryEquivalentTypes) + if args.SkipUnsafe { + unsafeEquality = noEquality{} + } + + targets = append(targets, + &generator.SimpleTarget{ + PkgName: path.Base(pkg.Path), + PkgPath: pkg.Path, + PkgDir: pkg.Dir, // output pkg is the same as the input + HeaderComment: boilerplate, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + return t.Name.Package == typesPkg.Path + }, + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + return []generator.Generator{ + NewGenConversion(args.OutputFile, typesPkg.Path, pkg.Path, manualConversions, pkgToPeers[pkg.Path], unsafeEquality), + } + }, + }) + } + + // If there is a manual conversion defined between two types, exclude it + // from being a candidate for unsafe conversion + for k, v := range manualConversions { + if isCopyOnly(v.CommentLines) { + klog.V(4).Infof("Conversion function %s will not block memory copy because it is copy-only", v.Name) + continue + } + // this type should be excluded from all equivalence, because the converter must be called. + memoryEquivalentTypes.Skip(k.inType, k.outType) + } + + return targets +} + +type equalMemoryTypes map[conversionPair]bool + +func (e equalMemoryTypes) Skip(a, b *types.Type) { + e[conversionPair{a, b}] = false + e[conversionPair{b, a}] = false +} + +func (e equalMemoryTypes) Equal(a, b *types.Type) bool { + // alreadyVisitedTypes holds all the types that have already been checked in the structural type recursion. + alreadyVisitedTypes := make(map[*types.Type]bool) + return e.cachingEqual(a, b, alreadyVisitedTypes) +} + +func (e equalMemoryTypes) cachingEqual(a, b *types.Type, alreadyVisitedTypes map[*types.Type]bool) bool { + if a == b { + return true + } + if equal, ok := e[conversionPair{a, b}]; ok { + return equal + } + if equal, ok := e[conversionPair{b, a}]; ok { + return equal + } + result := e.equal(a, b, alreadyVisitedTypes) + e[conversionPair{a, b}] = result + e[conversionPair{b, a}] = result + return result +} + +func (e equalMemoryTypes) equal(a, b *types.Type, alreadyVisitedTypes map[*types.Type]bool) bool { + in, out := unwrapAlias(a), unwrapAlias(b) + switch { + case in == out: + return true + case in.Kind == out.Kind: + // if the type exists already, return early to avoid recursion + if alreadyVisitedTypes[in] { + return true + } + alreadyVisitedTypes[in] = true + + switch in.Kind { + case types.Struct: + if len(in.Members) != len(out.Members) { + return false + } + for i, inMember := range in.Members { + outMember := out.Members[i] + if !e.cachingEqual(inMember.Type, outMember.Type, alreadyVisitedTypes) { + return false + } + } + return true + case types.Pointer: + return e.cachingEqual(in.Elem, out.Elem, alreadyVisitedTypes) + case types.Map: + return e.cachingEqual(in.Key, out.Key, alreadyVisitedTypes) && e.cachingEqual(in.Elem, out.Elem, alreadyVisitedTypes) + case types.Slice: + return e.cachingEqual(in.Elem, out.Elem, alreadyVisitedTypes) + case types.Interface: + // TODO: determine whether the interfaces are actually equivalent - for now, they must have the + // same type. + return false + case types.Builtin: + return in.Name.Name == out.Name.Name + } + } + return false +} + +func findMember(t *types.Type, name string) (types.Member, bool) { + if t.Kind != types.Struct { + return types.Member{}, false + } + for _, member := range t.Members { + if member.Name == name { + return member, true + } + } + return types.Member{}, false +} + +// unwrapAlias recurses down aliased types to find the bedrock type. +func unwrapAlias(in *types.Type) *types.Type { + for in.Kind == types.Alias { + in = in.Underlying + } + return in +} + +const ( + runtimePackagePath = "k8s.io/apimachinery/pkg/runtime" + conversionPackagePath = "k8s.io/apimachinery/pkg/conversion" +) + +type noEquality struct{} + +func (noEquality) Equal(_, _ *types.Type) bool { return false } + +type TypesEqual interface { + Equal(a, b *types.Type) bool +} + +// genConversion produces a file with a autogenerated conversions. +type genConversion struct { + generator.GoGenerator + // the package that contains the types that conversion func are going to be + // generated for + typesPackage string + // the package that the conversion funcs are going to be output to + outputPackage string + // packages that contain the peer of types in typesPacakge + peerPackages []string + manualConversions conversionFuncMap + imports namer.ImportTracker + types []*types.Type + explicitConversions []conversionPair + skippedFields map[*types.Type][]string + useUnsafe TypesEqual +} + +func NewGenConversion(outputFilename, typesPackage, outputPackage string, manualConversions conversionFuncMap, peerPkgs []string, useUnsafe TypesEqual) generator.Generator { + return &genConversion{ + GoGenerator: generator.GoGenerator{ + OutputFilename: outputFilename, + }, + typesPackage: typesPackage, + outputPackage: outputPackage, + peerPackages: peerPkgs, + manualConversions: manualConversions, + imports: generator.NewImportTrackerForPackage(outputPackage), + types: []*types.Type{}, + explicitConversions: []conversionPair{}, + skippedFields: map[*types.Type][]string{}, + useUnsafe: useUnsafe, + } +} + +func (g *genConversion) Namers(c *generator.Context) namer.NameSystems { + // Have the raw namer for this file track what it imports. + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + "publicIT": &namerPlusImportTracking{ + delegate: conversionNamer(), + tracker: g.imports, + }, + } +} + +type namerPlusImportTracking struct { + delegate namer.Namer + tracker namer.ImportTracker +} + +func (n *namerPlusImportTracking) Name(t *types.Type) string { + n.tracker.AddType(t) + return n.delegate.Name(t) +} + +func (g *genConversion) convertibleOnlyWithinPackage(inType, outType *types.Type) bool { + var t *types.Type + var other *types.Type + if inType.Name.Package == g.typesPackage { + t, other = inType, outType + } else { + t, other = outType, inType + } + + if t.Name.Package != g.typesPackage { + return false + } + // If the type has opted out, skip it. + tagvals := extractTag(t.CommentLines) + if tagvals != nil { + if tagvals[0] != "false" { + klog.Fatalf("Type %v: unsupported %s value: %q", t, tagName, tagvals[0]) + } + klog.V(2).Infof("type %v requests no conversion generation, skipping", t) + return false + } + // TODO: Consider generating functions for other kinds too. + if t.Kind != types.Struct { + return false + } + // Also, filter out private types. + if namer.IsPrivateGoName(other.Name.Name) { + return false + } + return true +} + +func getExplicitFromTypes(t *types.Type) []types.Name { + comments := t.SecondClosestCommentLines + comments = append(comments, t.CommentLines...) + paths := extractExplicitFromTag(comments) + result := []types.Name{} + for _, path := range paths { + items := strings.Split(path, ".") + if len(items) != 2 { + klog.Errorf("Unexpected k8s:conversion-gen:explicit-from tag: %s", path) + continue + } + switch { + case items[0] == "net/url" && items[1] == "Values": + default: + klog.Fatalf("Not supported k8s:conversion-gen:explicit-from tag: %s", path) + } + result = append(result, types.Name{Package: items[0], Name: items[1]}) + } + return result +} + +func (g *genConversion) Filter(c *generator.Context, t *types.Type) bool { + convertibleWithPeer := func() bool { + peerType := getPeerTypeFor(c, t, g.peerPackages) + if peerType == nil { + return false + } + if !g.convertibleOnlyWithinPackage(t, peerType) { + return false + } + g.types = append(g.types, t) + return true + }() + + explicitlyConvertible := func() bool { + inTypes := getExplicitFromTypes(t) + if len(inTypes) == 0 { + return false + } + for i := range inTypes { + pair := conversionPair{ + inType: &types.Type{Name: inTypes[i]}, + outType: t, + } + g.explicitConversions = append(g.explicitConversions, pair) + } + return true + }() + + return convertibleWithPeer || explicitlyConvertible +} + +func (g *genConversion) isOtherPackage(pkg string) bool { + if pkg == g.outputPackage { + return false + } + if strings.HasSuffix(pkg, `"`+g.outputPackage+`"`) { + return false + } + return true +} + +func (g *genConversion) Imports(c *generator.Context) (imports []string) { + var importLines []string + for _, singleImport := range g.imports.ImportLines() { + if g.isOtherPackage(singleImport) { + importLines = append(importLines, singleImport) + } + } + return importLines +} + +func argsFromType(inType, outType *types.Type) generator.Args { + return generator.Args{ + "inType": inType, + "outType": outType, + } +} + +const nameTmpl = "Convert_$.inType|publicIT$_To_$.outType|publicIT$" + +func (g *genConversion) preexists(inType, outType *types.Type) (*types.Type, bool) { + function, ok := g.manualConversions[conversionPair{inType, outType}] + return function, ok +} + +func (g *genConversion) Init(c *generator.Context, w io.Writer) error { + klogV := klog.V(6) + if klogV.Enabled() { + if m, ok := g.useUnsafe.(equalMemoryTypes); ok { + var result []string + klogV.Info("All objects without identical memory layout:") + for k, v := range m { + if v { + continue + } + result = append(result, fmt.Sprintf(" %s -> %s = %t", k.inType, k.outType, v)) + } + sort.Strings(result) + for _, s := range result { + klogV.Info(s) + } + } + } + sw := generator.NewSnippetWriter(w, c, "$", "$") + sw.Do("func init() {\n", nil) + sw.Do("localSchemeBuilder.Register(RegisterConversions)\n", nil) + sw.Do("}\n", nil) + + scheme := c.Universe.Type(types.Name{Package: runtimePackagePath, Name: "Scheme"}) + schemePtr := &types.Type{ + Kind: types.Pointer, + Elem: scheme, + } + sw.Do("// RegisterConversions adds conversion functions to the given scheme.\n", nil) + sw.Do("// Public to allow building arbitrary schemes.\n", nil) + sw.Do("func RegisterConversions(s $.|raw$) error {\n", schemePtr) + for _, t := range g.types { + peerType := getPeerTypeFor(c, t, g.peerPackages) + if _, found := g.preexists(t, peerType); !found { + args := argsFromType(t, peerType).With("Scope", types.Ref(conversionPackagePath, "Scope")) + sw.Do("if err := s.AddGeneratedConversionFunc((*$.inType|raw$)(nil), (*$.outType|raw$)(nil), func(a, b interface{}, scope $.Scope|raw$) error { return "+nameTmpl+"(a.(*$.inType|raw$), b.(*$.outType|raw$), scope) }); err != nil { return err }\n", args) + } + if _, found := g.preexists(peerType, t); !found { + args := argsFromType(peerType, t).With("Scope", types.Ref(conversionPackagePath, "Scope")) + sw.Do("if err := s.AddGeneratedConversionFunc((*$.inType|raw$)(nil), (*$.outType|raw$)(nil), func(a, b interface{}, scope $.Scope|raw$) error { return "+nameTmpl+"(a.(*$.inType|raw$), b.(*$.outType|raw$), scope) }); err != nil { return err }\n", args) + } + } + + for i := range g.explicitConversions { + args := argsFromType(g.explicitConversions[i].inType, g.explicitConversions[i].outType).With("Scope", types.Ref(conversionPackagePath, "Scope")) + sw.Do("if err := s.AddGeneratedConversionFunc((*$.inType|raw$)(nil), (*$.outType|raw$)(nil), func(a, b interface{}, scope $.Scope|raw$) error { return "+nameTmpl+"(a.(*$.inType|raw$), b.(*$.outType|raw$), scope) }); err != nil { return err }\n", args) + } + + var pairs []conversionPair + for pair, t := range g.manualConversions { + if t.Name.Package != g.outputPackage { + continue + } + pairs = append(pairs, pair) + } + // sort by name of the conversion function + sort.Slice(pairs, func(i, j int) bool { + return g.manualConversions[pairs[i]].Name.Name < g.manualConversions[pairs[j]].Name.Name + }) + for _, pair := range pairs { + args := argsFromType(pair.inType, pair.outType).With("Scope", types.Ref(conversionPackagePath, "Scope")).With("fn", g.manualConversions[pair]) + sw.Do("if err := s.AddConversionFunc((*$.inType|raw$)(nil), (*$.outType|raw$)(nil), func(a, b interface{}, scope $.Scope|raw$) error { return $.fn|raw$(a.(*$.inType|raw$), b.(*$.outType|raw$), scope) }); err != nil { return err }\n", args) + } + + sw.Do("return nil\n", nil) + sw.Do("}\n\n", nil) + return sw.Error() +} + +func (g *genConversion) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + klog.V(5).Infof("generating for type %v", t) + sw := generator.NewSnippetWriter(w, c, "$", "$") + + if peerType := getPeerTypeFor(c, t, g.peerPackages); peerType != nil { + g.generateConversion(t, peerType, sw) + g.generateConversion(peerType, t, sw) + } + + for _, inTypeName := range getExplicitFromTypes(t) { + inPkg, ok := c.Universe[inTypeName.Package] + if !ok { + klog.Errorf("Unrecognized package: %s", inTypeName.Package) + continue + } + inType, ok := inPkg.Types[inTypeName.Name] + if !ok { + klog.Errorf("Unrecognized type in package %s: %s", inTypeName.Package, inTypeName.Name) + continue + } + switch { + case inType.Name.Package == "net/url" && inType.Name.Name == "Values": + g.generateFromURLValues(inType, t, sw) + default: + klog.Errorf("Not supported input type: %#v", inType.Name) + } + } + + return sw.Error() +} + +func (g *genConversion) generateConversion(inType, outType *types.Type, sw *generator.SnippetWriter) { + args := argsFromType(inType, outType). + With("Scope", types.Ref(conversionPackagePath, "Scope")) + + sw.Do("func auto"+nameTmpl+"(in *$.inType|raw$, out *$.outType|raw$, s $.Scope|raw$) error {\n", args) + g.generateFor(inType, outType, sw) + sw.Do("return nil\n", nil) + sw.Do("}\n\n", nil) + + if _, found := g.preexists(inType, outType); found { + // There is a public manual Conversion method: use it. + } else if skipped := g.skippedFields[inType]; len(skipped) != 0 { + // The inType had some fields we could not generate. + klog.Errorf("Warning: could not find nor generate a final Conversion function for %v -> %v", inType, outType) + klog.Errorf(" the following fields need manual conversion:") + for _, f := range skipped { + klog.Errorf(" - %v", f) + } + } else { + // Emit a public conversion function. + sw.Do("// "+nameTmpl+" is an autogenerated conversion function.\n", args) + sw.Do("func "+nameTmpl+"(in *$.inType|raw$, out *$.outType|raw$, s $.Scope|raw$) error {\n", args) + sw.Do("return auto"+nameTmpl+"(in, out, s)\n", args) + sw.Do("}\n\n", nil) + } +} + +// we use the system of shadowing 'in' and 'out' so that the same code is valid +// at any nesting level. This makes the autogenerator easy to understand, and +// the compiler shouldn't care. +func (g *genConversion) generateFor(inType, outType *types.Type, sw *generator.SnippetWriter) { + klog.V(4).Infof("generating %v -> %v", inType, outType) + var f func(*types.Type, *types.Type, *generator.SnippetWriter) + + switch inType.Kind { + case types.Builtin: + f = g.doBuiltin + case types.Map: + f = g.doMap + case types.Slice: + f = g.doSlice + case types.Struct: + f = g.doStruct + case types.Pointer: + f = g.doPointer + case types.Alias: + f = g.doAlias + default: + f = g.doUnknown + } + + f(inType, outType, sw) +} + +func (g *genConversion) doBuiltin(inType, outType *types.Type, sw *generator.SnippetWriter) { + if inType == outType { + sw.Do("*out = *in\n", nil) + } else { + sw.Do("*out = $.|raw$(*in)\n", outType) + } +} + +func (g *genConversion) doMap(inType, outType *types.Type, sw *generator.SnippetWriter) { + sw.Do("*out = make($.|raw$, len(*in))\n", outType) + if isDirectlyAssignable(inType.Key, outType.Key) { + sw.Do("for key, val := range *in {\n", nil) + if isDirectlyAssignable(inType.Elem, outType.Elem) { + if inType.Key == outType.Key { + sw.Do("(*out)[key] = ", nil) + } else { + sw.Do("(*out)[$.|raw$(key)] = ", outType.Key) + } + if inType.Elem == outType.Elem { + sw.Do("val\n", nil) + } else { + sw.Do("$.|raw$(val)\n", outType.Elem) + } + } else { + conversionExists := true + if function, ok := g.preexists(inType.Elem, outType.Elem); ok { + sw.Do("newVal := new($.|raw$)\n", outType.Elem) + sw.Do("if err := $.|raw$(&val, newVal, s); err != nil {\n", function) + } else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) { + sw.Do("newVal := new($.|raw$)\n", outType.Elem) + sw.Do("if err := "+nameTmpl+"(&val, newVal, s); err != nil {\n", argsFromType(inType.Elem, outType.Elem)) + } else { + args := argsFromType(inType.Elem, outType.Elem) + sw.Do("// FIXME: Provide conversion function to convert $.inType|raw$ to $.outType|raw$\n", args) + sw.Do("compileErrorOnMissingConversion()\n", nil) + conversionExists = false + } + if conversionExists { + sw.Do("return err\n", nil) + sw.Do("}\n", nil) + if inType.Key == outType.Key { + sw.Do("(*out)[key] = *newVal\n", nil) + } else { + sw.Do("(*out)[$.|raw$(key)] = *newVal\n", outType.Key) + } + } + } + } else { + // TODO: Implement it when necessary. + sw.Do("for range *in {\n", nil) + sw.Do("// FIXME: Converting unassignable keys unsupported $.|raw$\n", inType.Key) + } + sw.Do("}\n", nil) +} + +func (g *genConversion) doSlice(inType, outType *types.Type, sw *generator.SnippetWriter) { + sw.Do("*out = make($.|raw$, len(*in))\n", outType) + if inType.Elem == outType.Elem && inType.Elem.Kind == types.Builtin { + sw.Do("copy(*out, *in)\n", nil) + } else { + sw.Do("for i := range *in {\n", nil) + if isDirectlyAssignable(inType.Elem, outType.Elem) { + if inType.Elem == outType.Elem { + sw.Do("(*out)[i] = (*in)[i]\n", nil) + } else { + sw.Do("(*out)[i] = $.|raw$((*in)[i])\n", outType.Elem) + } + } else { + conversionExists := true + if function, ok := g.preexists(inType.Elem, outType.Elem); ok { + sw.Do("if err := $.|raw$(&(*in)[i], &(*out)[i], s); err != nil {\n", function) + } else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) { + sw.Do("if err := "+nameTmpl+"(&(*in)[i], &(*out)[i], s); err != nil {\n", argsFromType(inType.Elem, outType.Elem)) + } else { + args := argsFromType(inType.Elem, outType.Elem) + sw.Do("// FIXME: Provide conversion function to convert $.inType|raw$ to $.outType|raw$\n", args) + sw.Do("compileErrorOnMissingConversion()\n", nil) + conversionExists = false + } + if conversionExists { + sw.Do("return err\n", nil) + sw.Do("}\n", nil) + } + } + sw.Do("}\n", nil) + } +} + +func (g *genConversion) doStruct(inType, outType *types.Type, sw *generator.SnippetWriter) { + for _, inMember := range inType.Members { + if tagvals := extractTag(inMember.CommentLines); tagvals != nil && tagvals[0] == "false" { + // This field is excluded from conversion. + sw.Do("// INFO: in."+inMember.Name+" opted out of conversion generation\n", nil) + continue + } + outMember, found := findMember(outType, inMember.Name) + if !found { + // This field doesn't exist in the peer. + sw.Do("// WARNING: in."+inMember.Name+" requires manual conversion: does not exist in peer-type\n", nil) + g.skippedFields[inType] = append(g.skippedFields[inType], inMember.Name) + continue + } + + inMemberType, outMemberType := inMember.Type, outMember.Type + // create a copy of both underlying types but give them the top level alias name (since aliases + // are assignable) + if underlying := unwrapAlias(inMemberType); underlying != inMemberType { + copied := *underlying + copied.Name = inMemberType.Name + inMemberType = &copied + } + if underlying := unwrapAlias(outMemberType); underlying != outMemberType { + copied := *underlying + copied.Name = outMemberType.Name + outMemberType = &copied + } + + args := argsFromType(inMemberType, outMemberType).With("name", inMember.Name) + + // try a direct memory copy for any type that has exactly equivalent values + if g.useUnsafe.Equal(inMemberType, outMemberType) { + args = args. + With("Pointer", types.Ref("unsafe", "Pointer")). + With("SliceHeader", types.Ref("reflect", "SliceHeader")) + switch inMemberType.Kind { + case types.Pointer: + sw.Do("out.$.name$ = ($.outType|raw$)($.Pointer|raw$(in.$.name$))\n", args) + continue + case types.Map: + sw.Do("out.$.name$ = *(*$.outType|raw$)($.Pointer|raw$(&in.$.name$))\n", args) + continue + case types.Slice: + sw.Do("out.$.name$ = *(*$.outType|raw$)($.Pointer|raw$(&in.$.name$))\n", args) + continue + } + } + + // check based on the top level name, not the underlying names + if function, ok := g.preexists(inMember.Type, outMember.Type); ok { + if isDrop(function.CommentLines) { + continue + } + // copy-only functions that are directly assignable can be inlined instead of invoked. + // As an example, conversion functions exist that allow types with private fields to be + // correctly copied between types. These functions are equivalent to a memory assignment, + // and are necessary for the reflection path, but should not block memory conversion. + // Convert_unversioned_Time_to_unversioned_Time is an example of this logic. + if !isCopyOnly(function.CommentLines) || !g.isFastConversion(inMemberType, outMemberType) { + args["function"] = function + sw.Do("if err := $.function|raw$(&in.$.name$, &out.$.name$, s); err != nil {\n", args) + sw.Do("return err\n", nil) + sw.Do("}\n", nil) + continue + } + klog.V(2).Infof("Skipped function %s because it is copy-only and we can use direct assignment", function.Name) + } + + // If we can't auto-convert, punt before we emit any code. + if inMemberType.Kind != outMemberType.Kind { + sw.Do("// WARNING: in."+inMember.Name+" requires manual conversion: inconvertible types ("+ + inMemberType.String()+" vs "+outMemberType.String()+")\n", nil) + g.skippedFields[inType] = append(g.skippedFields[inType], inMember.Name) + continue + } + + switch inMemberType.Kind { + case types.Builtin: + if inMemberType == outMemberType { + sw.Do("out.$.name$ = in.$.name$\n", args) + } else { + sw.Do("out.$.name$ = $.outType|raw$(in.$.name$)\n", args) + } + case types.Map, types.Slice, types.Pointer: + if g.isDirectlyAssignable(inMemberType, outMemberType) { + sw.Do("out.$.name$ = in.$.name$\n", args) + continue + } + + sw.Do("if in.$.name$ != nil {\n", args) + sw.Do("in, out := &in.$.name$, &out.$.name$\n", args) + g.generateFor(inMemberType, outMemberType, sw) + sw.Do("} else {\n", nil) + sw.Do("out.$.name$ = nil\n", args) + sw.Do("}\n", nil) + case types.Struct: + if g.isDirectlyAssignable(inMemberType, outMemberType) { + sw.Do("out.$.name$ = in.$.name$\n", args) + continue + } + conversionExists := true + if g.convertibleOnlyWithinPackage(inMemberType, outMemberType) { + sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args) + } else { + args := argsFromType(inMemberType, outMemberType) + sw.Do("// FIXME: Provide conversion function to convert $.inType|raw$ to $.outType|raw$\n", args) + sw.Do("compileErrorOnMissingConversion()\n", nil) + conversionExists = false + } + if conversionExists { + sw.Do("return err\n", nil) + sw.Do("}\n", nil) + } + case types.Alias: + if isDirectlyAssignable(inMemberType, outMemberType) { + if inMemberType == outMemberType { + sw.Do("out.$.name$ = in.$.name$\n", args) + } else { + sw.Do("out.$.name$ = $.outType|raw$(in.$.name$)\n", args) + } + } else { + conversionExists := true + if g.convertibleOnlyWithinPackage(inMemberType, outMemberType) { + sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args) + } else { + args := argsFromType(inMemberType, outMemberType) + sw.Do("// FIXME: Provide conversion function to convert $.inType|raw$ to $.outType|raw$\n", args) + sw.Do("compileErrorOnMissingConversion()\n", nil) + conversionExists = false + } + if conversionExists { + sw.Do("return err\n", nil) + sw.Do("}\n", nil) + } + } + default: + conversionExists := true + if g.convertibleOnlyWithinPackage(inMemberType, outMemberType) { + sw.Do("if err := "+nameTmpl+"(&in.$.name$, &out.$.name$, s); err != nil {\n", args) + } else { + args := argsFromType(inMemberType, outMemberType) + sw.Do("// FIXME: Provide conversion function to convert $.inType|raw$ to $.outType|raw$\n", args) + sw.Do("compileErrorOnMissingConversion()\n", nil) + conversionExists = false + } + if conversionExists { + sw.Do("return err\n", nil) + sw.Do("}\n", nil) + } + } + } +} + +func (g *genConversion) isFastConversion(inType, outType *types.Type) bool { + switch inType.Kind { + case types.Builtin: + return true + case types.Map, types.Slice, types.Pointer, types.Struct, types.Alias: + return g.isDirectlyAssignable(inType, outType) + default: + return false + } +} + +func (g *genConversion) isDirectlyAssignable(inType, outType *types.Type) bool { + return unwrapAlias(inType) == unwrapAlias(outType) +} + +func (g *genConversion) doPointer(inType, outType *types.Type, sw *generator.SnippetWriter) { + sw.Do("*out = new($.Elem|raw$)\n", outType) + if isDirectlyAssignable(inType.Elem, outType.Elem) { + if inType.Elem == outType.Elem { + sw.Do("**out = **in\n", nil) + } else { + sw.Do("**out = $.|raw$(**in)\n", outType.Elem) + } + } else { + conversionExists := true + if function, ok := g.preexists(inType.Elem, outType.Elem); ok { + sw.Do("if err := $.|raw$(*in, *out, s); err != nil {\n", function) + } else if g.convertibleOnlyWithinPackage(inType.Elem, outType.Elem) { + sw.Do("if err := "+nameTmpl+"(*in, *out, s); err != nil {\n", argsFromType(inType.Elem, outType.Elem)) + } else { + args := argsFromType(inType.Elem, outType.Elem) + sw.Do("// FIXME: Provide conversion function to convert $.inType|raw$ to $.outType|raw$\n", args) + sw.Do("compileErrorOnMissingConversion()\n", nil) + conversionExists = false + } + if conversionExists { + sw.Do("return err\n", nil) + sw.Do("}\n", nil) + } + } +} + +func (g *genConversion) doAlias(inType, outType *types.Type, sw *generator.SnippetWriter) { + // TODO: Add support for aliases. + g.doUnknown(inType, outType, sw) +} + +func (g *genConversion) doUnknown(inType, outType *types.Type, sw *generator.SnippetWriter) { + sw.Do("// FIXME: Type $.|raw$ is unsupported.\n", inType) +} + +func (g *genConversion) generateFromURLValues(inType, outType *types.Type, sw *generator.SnippetWriter) { + args := generator.Args{ + "inType": inType, + "outType": outType, + "Scope": types.Ref(conversionPackagePath, "Scope"), + } + sw.Do("func auto"+nameTmpl+"(in *$.inType|raw$, out *$.outType|raw$, s $.Scope|raw$) error {\n", args) + for _, outMember := range outType.Members { + if tagvals := extractTag(outMember.CommentLines); tagvals != nil && tagvals[0] == "false" { + // This field is excluded from conversion. + sw.Do("// INFO: in."+outMember.Name+" opted out of conversion generation\n", nil) + continue + } + jsonTag := reflect.StructTag(outMember.Tags).Get("json") + index := strings.Index(jsonTag, ",") + if index == -1 { + index = len(jsonTag) + } + if index == 0 { + memberArgs := generator.Args{ + "name": outMember.Name, + } + sw.Do("// WARNING: Field $.name$ does not have json tag, skipping.\n\n", memberArgs) + continue + } + memberArgs := generator.Args{ + "name": outMember.Name, + "tag": jsonTag[:index], + } + sw.Do("if values, ok := map[string][]string(*in)[\"$.tag$\"]; ok && len(values) > 0 {\n", memberArgs) + g.fromValuesEntry(inType.Underlying.Elem, outMember, sw) + sw.Do("} else {\n", nil) + g.setZeroValue(outMember, sw) + sw.Do("}\n", nil) + } + sw.Do("return nil\n", nil) + sw.Do("}\n\n", nil) + + if _, found := g.preexists(inType, outType); found { + // There is a public manual Conversion method: use it. + } else { + // Emit a public conversion function. + sw.Do("// "+nameTmpl+" is an autogenerated conversion function.\n", args) + sw.Do("func "+nameTmpl+"(in *$.inType|raw$, out *$.outType|raw$, s $.Scope|raw$) error {\n", args) + sw.Do("return auto"+nameTmpl+"(in, out, s)\n", args) + sw.Do("}\n\n", nil) + } +} + +func (g *genConversion) fromValuesEntry(inType *types.Type, outMember types.Member, sw *generator.SnippetWriter) { + memberArgs := generator.Args{ + "name": outMember.Name, + "type": outMember.Type, + } + if function, ok := g.preexists(inType, outMember.Type); ok { + args := memberArgs.With("function", function) + sw.Do("if err := $.function|raw$(&values, &out.$.name$, s); err != nil {\n", args) + sw.Do("return err\n", nil) + sw.Do("}\n", nil) + return + } + switch { + case outMember.Type == types.String: + sw.Do("out.$.name$ = values[0]\n", memberArgs) + case g.useUnsafe.Equal(inType, outMember.Type): + args := memberArgs.With("Pointer", types.Ref("unsafe", "Pointer")) + switch inType.Kind { + case types.Pointer: + sw.Do("out.$.name$ = ($.type|raw$)($.Pointer|raw$(&values))\n", args) + case types.Map, types.Slice: + sw.Do("out.$.name$ = *(*$.type|raw$)($.Pointer|raw$(&values))\n", args) + default: + // TODO: Support other types to allow more auto-conversions. + sw.Do("// FIXME: out.$.name$ is of not yet supported type and requires manual conversion\n", memberArgs) + } + default: + // TODO: Support other types to allow more auto-conversions. + sw.Do("// FIXME: out.$.name$ is of not yet supported type and requires manual conversion\n", memberArgs) + } +} + +func (g *genConversion) setZeroValue(outMember types.Member, sw *generator.SnippetWriter) { + outMemberType := unwrapAlias(outMember.Type) + memberArgs := generator.Args{ + "name": outMember.Name, + "alias": outMember.Type, + "type": outMemberType, + } + + switch outMemberType.Kind { + case types.Builtin: + switch outMemberType { + case types.String: + sw.Do("out.$.name$ = \"\"\n", memberArgs) + case types.Int64, types.Int32, types.Int16, types.Int, types.Uint64, types.Uint32, types.Uint16, types.Uint: + sw.Do("out.$.name$ = 0\n", memberArgs) + case types.Uintptr, types.Byte: + sw.Do("out.$.name$ = 0\n", memberArgs) + case types.Float64, types.Float32, types.Float: + sw.Do("out.$.name$ = 0\n", memberArgs) + case types.Bool: + sw.Do("out.$.name$ = false\n", memberArgs) + default: + sw.Do("// FIXME: out.$.name$ is of unsupported type and requires manual conversion\n", memberArgs) + } + case types.Struct: + if outMemberType == outMember.Type { + sw.Do("out.$.name$ = $.type|raw${}\n", memberArgs) + } else { + sw.Do("out.$.name$ = $.alias|raw$($.type|raw${})\n", memberArgs) + } + case types.Map, types.Slice, types.Pointer: + sw.Do("out.$.name$ = nil\n", memberArgs) + case types.Alias: + // outMemberType was already unwrapped from aliases - so that should never happen. + sw.Do("// FIXME: unexpected error for out.$.name$\n", memberArgs) + case types.Interface, types.Array: + sw.Do("out.$.name$ = nil\n", memberArgs) + default: + sw.Do("// FIXME: out.$.name$ is of unsupported type and requires manual conversion\n", memberArgs) + } +} + +func isDirectlyAssignable(inType, outType *types.Type) bool { + // TODO: This should maybe check for actual assignability between the two + // types, rather than superficial traits that happen to indicate it is + // assignable in the ways we currently use this code. + return inType.IsAssignable() && (inType.IsPrimitive() || isSamePackage(inType, outType)) +} + +func isSamePackage(inType, outType *types.Type) bool { + return inType.Name.Package == outType.Name.Package +} diff --git a/code-generator/cmd/conversion-gen/main.go b/code-generator/cmd/conversion-gen/main.go new file mode 100644 index 000000000..cd52a9b96 --- /dev/null +++ b/code-generator/cmd/conversion-gen/main.go @@ -0,0 +1,137 @@ +/* +Copyright 2016 The Kubernetes 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. +*/ + +// conversion-gen is a tool for auto-generating functions that convert +// between internal and external types. A general conversion code +// generation task involves three sets of packages: (1) a set of +// packages containing internal types, (2) a single package containing +// the external types, and (3) a single destination package (i.e., +// where the generated conversion functions go, and where the +// developer-authored conversion functions are). The packages +// containing the internal types play the role known as "peer +// packages" in the general code-generation framework of Kubernetes. +// +// For each conversion task, `conversion-gen` will generate functions +// that efficiently convert between same-name types in the two +// (internal, external) packages. The generated functions include +// ones named +// +// autoConvert___To__ +// +// for each such pair of types --- both with (pkg1,pkg2) = +// (internal,external) and (pkg1,pkg2) = (external,internal). The +// generated conversion functions recurse on the structure of the data +// types. For structs, source and destination fields are matched up +// according to name; if a source field has no corresponding +// destination or there is a fundamental mismatch in the type of the +// field then the generated autoConvert_... function has just a +// warning comment about that field. The generated conversion +// functions use standard value assignment wherever possible. For +// compound types, the generated conversion functions call the +// `Convert...` functions for the subsidiary types. +// +// For each pair of types `conversion-gen` will also generate a +// function named +// +// Convert___To__ +// +// if both of two conditions are met: (1) the destination package does +// not contain a function of that name in a non-generated file and (2) +// the generation of the corresponding autoConvert_... function did +// not run into trouble with a missing or fundamentally differently +// typed field. A generated Convert_... function simply calls the +// corresponding `autoConvert...` function. `conversion_gen` also +// generates a function that updates a given `runtime.Scheme` by +// registering all the Convert_... functions found and generated. +// Thus developers can override the generated behavior for selected +// type pairs by putting the desired Convert_... functions in +// non-generated files. Further, developers are practically required +// to override the generated behavior when there are missing or +// fundamentally differently typed fields. +// +// `conversion-gen` will scan its `--input-dirs`, looking at the +// package defined in each of those directories for comment tags that +// define a conversion code generation task. A package requests +// conversion code generation by including one or more comment in the +// package's `doc.go` file (currently anywhere in that file is +// acceptable, but the recommended location is above the `package` +// statement), of the form: +// +// // +k8s:conversion-gen= +// +// This introduces a conversion task, for which the destination +// package is the one containing the file with the tag and the tag +// identifies a package containing internal types. If there is also a +// tag of the form +// +// // +k8s:conversion-gen-external-types= +// +// then it identifies the package containing the external types; +// otherwise they are in the destination package. +// +// For each conversion code generation task, the full set of internal +// packages (AKA peer packages) consists of the ones specified in the +// `k8s:conversion-gen` tags PLUS any specified in the +// `--base-peer-dirs` and `--extra-peer-dirs` flags on the command +// line. +// +// When generating for a package, individual types or fields of structs may opt +// out of Conversion generation by specifying a comment on the of the form: +// +// // +k8s:conversion-gen=false +package main + +import ( + "flag" + + "github.com/spf13/pflag" + "k8s.io/klog/v2" + + generatorargs "k8s.io/code-generator/cmd/conversion-gen/args" + "k8s.io/code-generator/cmd/conversion-gen/generators" + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" +) + +func main() { + klog.InitFlags(nil) + args := generatorargs.New() + + args.AddFlags(pflag.CommandLine) + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + if err := args.Validate(); err != nil { + klog.Fatalf("Error: %v", err) + } + + myTargets := func(context *generator.Context) []generator.Target { + return generators.GetTargets(context, args) + } + + // Run it. + if err := gengo.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + myTargets, + gengo.StdBuildTag, + pflag.Args(), + ); err != nil { + klog.Fatalf("Error: %v", err) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/code-generator/cmd/deepcopy-gen/args/args.go b/code-generator/cmd/deepcopy-gen/args/args.go new file mode 100644 index 000000000..f5207a980 --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/args/args.go @@ -0,0 +1,52 @@ +/* +Copyright 2016 The Kubernetes 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" +) + +type Args struct { + OutputFile string + BoundingDirs []string // Only deal with types rooted under these dirs. + GoHeaderFile string +} + +// New returns default arguments for the generator. +func New() *Args { + return &Args{} +} + +// AddFlags add the generator flags to the flag set. +func (args *Args) AddFlags(fs *pflag.FlagSet) { + fs.StringVar(&args.OutputFile, "output-file", "generated.deepcopy.go", + "the name of the file to be generated") + fs.StringSliceVar(&args.BoundingDirs, "bounding-dirs", args.BoundingDirs, + "Comma-separated list of import paths which bound the types for which deep-copies will be generated.") + fs.StringVar(&args.GoHeaderFile, "go-header-file", "", + "the path to a file containing boilerplate header text; the string \"YEAR\" will be replaced with the current 4-digit year") +} + +// Validate checks the given arguments. +func (args *Args) Validate() error { + if len(args.OutputFile) == 0 { + return fmt.Errorf("--output-file must be specified") + } + return nil +} diff --git a/code-generator/cmd/deepcopy-gen/generators/deepcopy.go b/code-generator/cmd/deepcopy-gen/generators/deepcopy.go new file mode 100644 index 000000000..e1a8e4c16 --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/generators/deepcopy.go @@ -0,0 +1,892 @@ +/* +Copyright 2015 The Kubernetes 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 ( + "fmt" + "io" + "path" + "sort" + "strings" + + "k8s.io/code-generator/cmd/deepcopy-gen/args" + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + "k8s.io/klog/v2" +) + +// This is the comment tag that carries parameters for deep-copy generation. +const ( + tagEnabledName = "k8s:deepcopy-gen" + interfacesTagName = tagEnabledName + ":interfaces" + interfacesNonPointerTagName = tagEnabledName + ":nonpointer-interfaces" // attach the DeepCopy methods to the +) + +// Known values for the comment tag. +const tagValuePackage = "package" + +// enabledTagValue holds parameters from a tagName tag. +type enabledTagValue struct { + value string + register bool +} + +func extractEnabledTypeTag(t *types.Type) *enabledTagValue { + comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...) + return extractEnabledTag(comments) +} + +func extractEnabledTag(comments []string) *enabledTagValue { + tagVals := gengo.ExtractCommentTags("+", comments)[tagEnabledName] + if tagVals == nil { + // No match for the tag. + return nil + } + // If there are multiple values, abort. + if len(tagVals) > 1 { + klog.Fatalf("Found %d %s tags: %q", len(tagVals), tagEnabledName, tagVals) + } + + // If we got here we are returning something. + tag := &enabledTagValue{} + + // Get the primary value. + parts := strings.Split(tagVals[0], ",") + if len(parts) >= 1 { + tag.value = parts[0] + } + + // Parse extra arguments. + parts = parts[1:] + for i := range parts { + kv := strings.SplitN(parts[i], "=", 2) + k := kv[0] + v := "" + if len(kv) == 2 { + v = kv[1] + } + switch k { + case "register": + if v != "false" { + tag.register = true + } + default: + klog.Fatalf("Unsupported %s param: %q", tagEnabledName, parts[i]) + } + } + return tag +} + +// TODO: This is created only to reduce number of changes in a single PR. +// Remove it and use PublicNamer instead. +func deepCopyNamer() *namer.NameStrategy { + return &namer.NameStrategy{ + Join: func(pre string, in []string, post string) string { + return strings.Join(in, "_") + }, + PrependPackageNames: 1, + } +} + +// NameSystems returns the name system used by the generators in this package. +func NameSystems() namer.NameSystems { + return namer.NameSystems{ + "public": deepCopyNamer(), + "raw": namer.NewRawNamer("", nil), + } +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +func GetTargets(context *generator.Context, args *args.Args) []generator.Target { + boilerplate, err := gengo.GoBoilerplate(args.GoHeaderFile, gengo.StdBuildTag, gengo.StdGeneratedBy) + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + boundingDirs := []string{} + if args.BoundingDirs == nil { + args.BoundingDirs = context.Inputs + } + for i := range args.BoundingDirs { + // Strip any trailing slashes - they are not exactly "correct" but + // this is friendlier. + boundingDirs = append(boundingDirs, strings.TrimRight(args.BoundingDirs[i], "/")) + } + + targets := []generator.Target{} + + for _, i := range context.Inputs { + klog.V(3).Infof("Considering pkg %q", i) + + pkg := context.Universe[i] + + ptag := extractEnabledTag(pkg.Comments) + ptagValue := "" + ptagRegister := false + if ptag != nil { + ptagValue = ptag.value + if ptagValue != tagValuePackage { + klog.Fatalf("Package %v: unsupported %s value: %q", i, tagEnabledName, ptagValue) + } + ptagRegister = ptag.register + klog.V(3).Infof(" tag.value: %q, tag.register: %t", ptagValue, ptagRegister) + } else { + klog.V(3).Infof(" no tag") + } + + // If the pkg-scoped tag says to generate, we can skip scanning types. + pkgNeedsGeneration := (ptagValue == tagValuePackage) + if !pkgNeedsGeneration { + // If the pkg-scoped tag did not exist, scan all types for one that + // explicitly wants generation. Ensure all types that want generation + // can be copied. + var uncopyable []string + for _, t := range pkg.Types { + klog.V(3).Infof(" considering type %q", t.Name.String()) + ttag := extractEnabledTypeTag(t) + if ttag != nil && ttag.value == "true" { + klog.V(3).Infof(" tag=true") + if !copyableType(t) { + uncopyable = append(uncopyable, fmt.Sprintf("%v", t)) + } else { + pkgNeedsGeneration = true + } + } + } + if len(uncopyable) > 0 { + klog.Fatalf("Types requested deepcopy generation but are not copyable: %s", + strings.Join(uncopyable, ", ")) + } + } + + if pkgNeedsGeneration { + klog.V(3).Infof("Package %q needs generation", i) + targets = append(targets, + &generator.SimpleTarget{ + PkgName: strings.Split(path.Base(pkg.Path), ".")[0], + PkgPath: pkg.Path, + PkgDir: pkg.Dir, // output pkg is the same as the input + HeaderComment: boilerplate, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + return t.Name.Package == pkg.Path + }, + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + return []generator.Generator{ + NewGenDeepCopy(args.OutputFile, pkg.Path, boundingDirs, (ptagValue == tagValuePackage), ptagRegister), + } + }, + }) + } + } + return targets +} + +// genDeepCopy produces a file with autogenerated deep-copy functions. +type genDeepCopy struct { + generator.GoGenerator + targetPackage string + boundingDirs []string + allTypes bool + registerTypes bool + imports namer.ImportTracker + typesForInit []*types.Type +} + +func NewGenDeepCopy(outputFilename, targetPackage string, boundingDirs []string, allTypes, registerTypes bool) generator.Generator { + return &genDeepCopy{ + GoGenerator: generator.GoGenerator{ + OutputFilename: outputFilename, + }, + targetPackage: targetPackage, + boundingDirs: boundingDirs, + allTypes: allTypes, + registerTypes: registerTypes, + imports: generator.NewImportTrackerForPackage(targetPackage), + typesForInit: make([]*types.Type, 0), + } +} + +func (g *genDeepCopy) Namers(c *generator.Context) namer.NameSystems { + // Have the raw namer for this file track what it imports. + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.targetPackage, g.imports), + } +} + +func (g *genDeepCopy) Filter(c *generator.Context, t *types.Type) bool { + // Filter out types not being processed or not copyable within the package. + enabled := g.allTypes + if !enabled { + ttag := extractEnabledTypeTag(t) + if ttag != nil && ttag.value == "true" { + enabled = true + } + } + if !enabled { + return false + } + if !copyableType(t) { + klog.V(3).Infof("Type %v is not copyable", t) + return false + } + klog.V(3).Infof("Type %v is copyable", t) + g.typesForInit = append(g.typesForInit, t) + return true +} + +// deepCopyMethod returns the signature of a DeepCopy() method, nil or an error +// if the type does not match. This allows more efficient deep copy +// implementations to be defined by the type's author. The correct signature +// for a type T is: +// +// func (t T) DeepCopy() T +// +// or: +// +// func (t *T) DeepCopy() *T +func deepCopyMethod(t *types.Type) (*types.Signature, error) { + f, found := t.Methods["DeepCopy"] + if !found { + return nil, nil + } + if len(f.Signature.Parameters) != 0 { + return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected no parameters", t) + } + if len(f.Signature.Results) != 1 { + return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected exactly one result", t) + } + + ptrResult := f.Signature.Results[0].Type.Kind == types.Pointer && f.Signature.Results[0].Type.Elem.Name == t.Name + nonPtrResult := f.Signature.Results[0].Type.Name == t.Name + + if !ptrResult && !nonPtrResult { + return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected to return %s or *%s", t, t.Name.Name, t.Name.Name) + } + + ptrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Kind == types.Pointer && f.Signature.Receiver.Elem.Name == t.Name + nonPtrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Name == t.Name + + if ptrRcvr && !ptrResult { + return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected a *%s result for a *%s receiver", t, t.Name.Name, t.Name.Name) + } + if nonPtrRcvr && !nonPtrResult { + return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected a %s result for a %s receiver", t, t.Name.Name, t.Name.Name) + } + + return f.Signature, nil +} + +// deepCopyMethodOrDie returns the signatrue of a DeepCopy method, nil or calls klog.Fatalf +// if the type does not match. +func deepCopyMethodOrDie(t *types.Type) *types.Signature { + ret, err := deepCopyMethod(t) + if err != nil { + klog.Fatal(err) + } + return ret +} + +// deepCopyIntoMethod returns the signature of a DeepCopyInto() method, nil or an error +// if the type is wrong. DeepCopyInto allows more efficient deep copy +// implementations to be defined by the type's author. The correct signature +// for a type T is: +// +// func (t T) DeepCopyInto(t *T) +// +// or: +// +// func (t *T) DeepCopyInto(t *T) +func deepCopyIntoMethod(t *types.Type) (*types.Signature, error) { + f, found := t.Methods["DeepCopyInto"] + if !found { + return nil, nil + } + if len(f.Signature.Parameters) != 1 { + return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected exactly one parameter", t) + } + if len(f.Signature.Results) != 0 { + return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected no result type", t) + } + + ptrParam := f.Signature.Parameters[0].Type.Kind == types.Pointer && f.Signature.Parameters[0].Type.Elem.Name == t.Name + + if !ptrParam { + return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected parameter of type *%s", t, t.Name.Name) + } + + ptrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Kind == types.Pointer && f.Signature.Receiver.Elem.Name == t.Name + nonPtrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Name == t.Name + + if !ptrRcvr && !nonPtrRcvr { + // this should never happen + return nil, fmt.Errorf("type %v: invalid DeepCopy signature, expected a receiver of type %s or *%s", t, t.Name.Name, t.Name.Name) + } + + return f.Signature, nil +} + +// deepCopyIntoMethodOrDie returns the signature of a DeepCopyInto() method, nil or calls klog.Fatalf +// if the type is wrong. +func deepCopyIntoMethodOrDie(t *types.Type) *types.Signature { + ret, err := deepCopyIntoMethod(t) + if err != nil { + klog.Fatal(err) + } + return ret +} + +func copyableType(t *types.Type) bool { + // If the type opts out of copy-generation, stop. + ttag := extractEnabledTypeTag(t) + if ttag != nil && ttag.value == "false" { + return false + } + + // Filter out private types. + if namer.IsPrivateGoName(t.Name.Name) { + return false + } + + if t.Kind == types.Alias { + // if the underlying built-in is not deepcopy-able, deepcopy is opt-in through definition of custom methods. + // Note that aliases of builtins, maps, slices can have deepcopy methods. + if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil { + return true + } else { + return t.Underlying.Kind != types.Builtin || copyableType(t.Underlying) + } + } + + if t.Kind != types.Struct { + return false + } + + return true +} + +func underlyingType(t *types.Type) *types.Type { + for t.Kind == types.Alias { + t = t.Underlying + } + return t +} + +func (g *genDeepCopy) isOtherPackage(pkg string) bool { + if pkg == g.targetPackage { + return false + } + if strings.HasSuffix(pkg, "\""+g.targetPackage+"\"") { + return false + } + return true +} + +func (g *genDeepCopy) Imports(c *generator.Context) (imports []string) { + importLines := []string{} + for _, singleImport := range g.imports.ImportLines() { + if g.isOtherPackage(singleImport) { + importLines = append(importLines, singleImport) + } + } + return importLines +} + +func argsFromType(ts ...*types.Type) generator.Args { + a := generator.Args{ + "type": ts[0], + } + for i, t := range ts { + a[fmt.Sprintf("type%d", i+1)] = t + } + return a +} + +func (g *genDeepCopy) Init(c *generator.Context, w io.Writer) error { + return nil +} + +func (g *genDeepCopy) needsGeneration(t *types.Type) bool { + tag := extractEnabledTypeTag(t) + tv := "" + if tag != nil { + tv = tag.value + if tv != "true" && tv != "false" { + klog.Fatalf("Type %v: unsupported %s value: %q", t, tagEnabledName, tag.value) + } + } + if g.allTypes && tv == "false" { + // The whole package is being generated, but this type has opted out. + klog.V(2).Infof("Not generating for type %v because type opted out", t) + return false + } + if !g.allTypes && tv != "true" { + // The whole package is NOT being generated, and this type has NOT opted in. + klog.V(2).Infof("Not generating for type %v because type did not opt in", t) + return false + } + return true +} + +func extractInterfacesTag(t *types.Type) []string { + var result []string + comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...) + values := gengo.ExtractCommentTags("+", comments)[interfacesTagName] + for _, v := range values { + if len(v) == 0 { + continue + } + intfs := strings.Split(v, ",") + for _, intf := range intfs { + if intf == "" { + continue + } + result = append(result, intf) + } + } + return result +} + +func extractNonPointerInterfaces(t *types.Type) (bool, error) { + comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...) + values := gengo.ExtractCommentTags("+", comments)[interfacesNonPointerTagName] + if len(values) == 0 { + return false, nil + } + result := values[0] == "true" + for _, v := range values { + if v == "true" != result { + return false, fmt.Errorf("contradicting %v value %q found to previous value %v", interfacesNonPointerTagName, v, result) + } + } + return result, nil +} + +func (g *genDeepCopy) deepCopyableInterfacesInner(c *generator.Context, t *types.Type) ([]*types.Type, error) { + if t.Kind != types.Struct { + return nil, nil + } + + intfs := extractInterfacesTag(t) + + var ts []*types.Type + for _, intf := range intfs { + t := types.ParseFullyQualifiedName(intf) + klog.V(3).Infof("Loading package for interface %v", intf) + _, err := c.LoadPackages(t.Package) + if err != nil { + return nil, err + } + intfT := c.Universe.Type(t) + if intfT == nil { + return nil, fmt.Errorf("unknown type %q in %s tag of type %s", intf, interfacesTagName, intfT) + } + if intfT.Kind != types.Interface { + return nil, fmt.Errorf("type %q in %s tag of type %s is not an interface, but: %q", intf, interfacesTagName, t, intfT.Kind) + } + g.imports.AddType(intfT) + ts = append(ts, intfT) + } + + return ts, nil +} + +// deepCopyableInterfaces returns the interface types to implement and whether they apply to a non-pointer receiver. +func (g *genDeepCopy) deepCopyableInterfaces(c *generator.Context, t *types.Type) ([]*types.Type, bool, error) { + ts, err := g.deepCopyableInterfacesInner(c, t) + if err != nil { + return nil, false, err + } + + set := map[string]*types.Type{} + for _, t := range ts { + set[t.String()] = t + } + + result := []*types.Type{} + for _, t := range set { + result = append(result, t) + } + + TypeSlice(result).Sort() // we need a stable sorting because it determines the order in generation + + nonPointerReceiver, err := extractNonPointerInterfaces(t) + if err != nil { + return nil, false, err + } + + return result, nonPointerReceiver, nil +} + +type TypeSlice []*types.Type + +func (s TypeSlice) Len() int { return len(s) } +func (s TypeSlice) Less(i, j int) bool { return s[i].String() < s[j].String() } +func (s TypeSlice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s TypeSlice) Sort() { sort.Sort(s) } + +func (g *genDeepCopy) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + if !g.needsGeneration(t) { + return nil + } + klog.V(2).Infof("Generating deepcopy functions for type %v", t) + + sw := generator.NewSnippetWriter(w, c, "$", "$") + args := argsFromType(t) + + if deepCopyIntoMethodOrDie(t) == nil { + sw.Do("// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.\n", args) + if isReference(t) { + sw.Do("func (in $.type|raw$) DeepCopyInto(out *$.type|raw$) {\n", args) + sw.Do("{in:=&in\n", nil) + } else { + sw.Do("func (in *$.type|raw$) DeepCopyInto(out *$.type|raw$) {\n", args) + } + if deepCopyMethodOrDie(t) != nil { + if t.Methods["DeepCopy"].Signature.Receiver.Kind == types.Pointer { + sw.Do("clone := in.DeepCopy()\n", nil) + sw.Do("*out = *clone\n", nil) + } else { + sw.Do("*out = in.DeepCopy()\n", nil) + } + sw.Do("return\n", nil) + } else { + g.generateFor(t, sw) + sw.Do("return\n", nil) + } + if isReference(t) { + sw.Do("}\n", nil) + } + sw.Do("}\n\n", nil) + } + + if deepCopyMethodOrDie(t) == nil { + sw.Do("// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new $.type|raw$.\n", args) + if isReference(t) { + sw.Do("func (in $.type|raw$) DeepCopy() $.type|raw$ {\n", args) + } else { + sw.Do("func (in *$.type|raw$) DeepCopy() *$.type|raw$ {\n", args) + } + sw.Do("if in == nil { return nil }\n", nil) + sw.Do("out := new($.type|raw$)\n", args) + sw.Do("in.DeepCopyInto(out)\n", nil) + if isReference(t) { + sw.Do("return *out\n", nil) + } else { + sw.Do("return out\n", nil) + } + sw.Do("}\n\n", nil) + } + + intfs, nonPointerReceiver, err := g.deepCopyableInterfaces(c, t) + if err != nil { + return err + } + for _, intf := range intfs { + sw.Do(fmt.Sprintf("// DeepCopy%s is an autogenerated deepcopy function, copying the receiver, creating a new $.type2|raw$.\n", intf.Name.Name), argsFromType(t, intf)) + if nonPointerReceiver { + sw.Do(fmt.Sprintf("func (in $.type|raw$) DeepCopy%s() $.type2|raw$ {\n", intf.Name.Name), argsFromType(t, intf)) + sw.Do("return *in.DeepCopy()", nil) + sw.Do("}\n\n", nil) + } else { + sw.Do(fmt.Sprintf("func (in *$.type|raw$) DeepCopy%s() $.type2|raw$ {\n", intf.Name.Name), argsFromType(t, intf)) + sw.Do("if c := in.DeepCopy(); c != nil {\n", nil) + sw.Do("return c\n", nil) + sw.Do("}\n", nil) + sw.Do("return nil\n", nil) + sw.Do("}\n\n", nil) + } + } + + return sw.Error() +} + +// isReference return true for pointer, maps, slices and aliases of those. +func isReference(t *types.Type) bool { + if t.Kind == types.Pointer || t.Kind == types.Map || t.Kind == types.Slice { + return true + } + return t.Kind == types.Alias && isReference(underlyingType(t)) +} + +// we use the system of shadowing 'in' and 'out' so that the same code is valid +// at any nesting level. This makes the autogenerator easy to understand, and +// the compiler shouldn't care. +func (g *genDeepCopy) generateFor(t *types.Type, sw *generator.SnippetWriter) { + // derive inner types if t is an alias. We call the do* methods below with the alias type. + // basic rule: generate according to inner type, but construct objects with the alias type. + ut := underlyingType(t) + + var f func(*types.Type, *generator.SnippetWriter) + switch ut.Kind { + case types.Builtin: + f = g.doBuiltin + case types.Map: + f = g.doMap + case types.Slice: + f = g.doSlice + case types.Struct: + f = g.doStruct + case types.Pointer: + f = g.doPointer + case types.Interface: + // interfaces are handled in-line in the other cases + klog.Fatalf("Hit an interface type %v. This should never happen.", t) + case types.Alias: + // can never happen because we branch on the underlying type which is never an alias + klog.Fatalf("Hit an alias type %v. This should never happen.", t) + default: + klog.Fatalf("Hit an unsupported type %v.", t) + } + f(t, sw) +} + +// doBuiltin generates code for a builtin or an alias to a builtin. The generated code is +// is the same for both cases, i.e. it's the code for the underlying type. +func (g *genDeepCopy) doBuiltin(t *types.Type, sw *generator.SnippetWriter) { + if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil { + sw.Do("*out = in.DeepCopy()\n", nil) + return + } + + sw.Do("*out = *in\n", nil) +} + +// doMap generates code for a map or an alias to a map. The generated code is +// is the same for both cases, i.e. it's the code for the underlying type. +func (g *genDeepCopy) doMap(t *types.Type, sw *generator.SnippetWriter) { + ut := underlyingType(t) + uet := underlyingType(ut.Elem) + + if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil { + sw.Do("*out = in.DeepCopy()\n", nil) + return + } + + if !ut.Key.IsAssignable() { + klog.Fatalf("Hit an unsupported type %v for: %v", uet, t) + } + + sw.Do("*out = make($.|raw$, len(*in))\n", t) + sw.Do("for key, val := range *in {\n", nil) + dc, dci := deepCopyMethodOrDie(ut.Elem), deepCopyIntoMethodOrDie(ut.Elem) + switch { + case dc != nil || dci != nil: + // Note: a DeepCopy exists because it is added if DeepCopyInto is manually defined + leftPointer := ut.Elem.Kind == types.Pointer + rightPointer := !isReference(ut.Elem) + if dc != nil { + rightPointer = dc.Results[0].Type.Kind == types.Pointer + } + if leftPointer == rightPointer { + sw.Do("(*out)[key] = val.DeepCopy()\n", nil) + } else if leftPointer { + sw.Do("x := val.DeepCopy()\n", nil) + sw.Do("(*out)[key] = &x\n", nil) + } else { + sw.Do("(*out)[key] = *val.DeepCopy()\n", nil) + } + case ut.Elem.IsAnonymousStruct(): // not uet here because it needs type cast + sw.Do("(*out)[key] = val\n", nil) + case uet.IsAssignable(): + sw.Do("(*out)[key] = val\n", nil) + case uet.Kind == types.Interface: + // Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function + if uet.Name.Name == "interface{}" { + klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy as one of the methods.", uet.Name.Name) + } + sw.Do("if val == nil {(*out)[key]=nil} else {\n", nil) + // Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it + // as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang + // parser does not give us the underlying interface name. So we cannot do any better. + sw.Do(fmt.Sprintf("(*out)[key] = val.DeepCopy%s()\n", uet.Name.Name), nil) + sw.Do("}\n", nil) + case uet.Kind == types.Slice || uet.Kind == types.Map || uet.Kind == types.Pointer: + sw.Do("var outVal $.|raw$\n", uet) + sw.Do("if val == nil { (*out)[key] = nil } else {\n", nil) + sw.Do("in, out := &val, &outVal\n", uet) + g.generateFor(ut.Elem, sw) + sw.Do("}\n", nil) + sw.Do("(*out)[key] = outVal\n", nil) + case uet.Kind == types.Struct: + sw.Do("(*out)[key] = *val.DeepCopy()\n", uet) + default: + klog.Fatalf("Hit an unsupported type %v for %v", uet, t) + } + sw.Do("}\n", nil) +} + +// doSlice generates code for a slice or an alias to a slice. The generated code is +// is the same for both cases, i.e. it's the code for the underlying type. +func (g *genDeepCopy) doSlice(t *types.Type, sw *generator.SnippetWriter) { + ut := underlyingType(t) + uet := underlyingType(ut.Elem) + + if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil { + sw.Do("*out = in.DeepCopy()\n", nil) + return + } + + sw.Do("*out = make($.|raw$, len(*in))\n", t) + if deepCopyMethodOrDie(ut.Elem) != nil || deepCopyIntoMethodOrDie(ut.Elem) != nil { + sw.Do("for i := range *in {\n", nil) + // Note: a DeepCopyInto exists because it is added if DeepCopy is manually defined + sw.Do("(*in)[i].DeepCopyInto(&(*out)[i])\n", nil) + sw.Do("}\n", nil) + } else if uet.Kind == types.Builtin || uet.IsAssignable() { + sw.Do("copy(*out, *in)\n", nil) + } else { + sw.Do("for i := range *in {\n", nil) + if uet.Kind == types.Slice || uet.Kind == types.Map || uet.Kind == types.Pointer || deepCopyMethodOrDie(ut.Elem) != nil || deepCopyIntoMethodOrDie(ut.Elem) != nil { + sw.Do("if (*in)[i] != nil {\n", nil) + sw.Do("in, out := &(*in)[i], &(*out)[i]\n", nil) + g.generateFor(ut.Elem, sw) + sw.Do("}\n", nil) + } else if uet.Kind == types.Interface { + // Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function + if uet.Name.Name == "interface{}" { + klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy as one of the methods.", uet.Name.Name) + } + sw.Do("if (*in)[i] != nil {\n", nil) + // Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it + // as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang + // parser does not give us the underlying interface name. So we cannot do any better. + sw.Do(fmt.Sprintf("(*out)[i] = (*in)[i].DeepCopy%s()\n", uet.Name.Name), nil) + sw.Do("}\n", nil) + } else if uet.Kind == types.Struct { + sw.Do("(*in)[i].DeepCopyInto(&(*out)[i])\n", nil) + } else { + klog.Fatalf("Hit an unsupported type %v for %v", uet, t) + } + sw.Do("}\n", nil) + } +} + +// doStruct generates code for a struct or an alias to a struct. The generated code is +// is the same for both cases, i.e. it's the code for the underlying type. +func (g *genDeepCopy) doStruct(t *types.Type, sw *generator.SnippetWriter) { + ut := underlyingType(t) + + if deepCopyMethodOrDie(t) != nil || deepCopyIntoMethodOrDie(t) != nil { + sw.Do("*out = in.DeepCopy()\n", nil) + return + } + + // Simple copy covers a lot of cases. + sw.Do("*out = *in\n", nil) + + // Now fix-up fields as needed. + for _, m := range ut.Members { + ft := m.Type + uft := underlyingType(ft) + + args := generator.Args{ + "type": ft, + "kind": ft.Kind, + "name": m.Name, + } + dc, dci := deepCopyMethodOrDie(ft), deepCopyIntoMethodOrDie(ft) + switch { + case dc != nil || dci != nil: + // Note: a DeepCopyInto exists because it is added if DeepCopy is manually defined + leftPointer := ft.Kind == types.Pointer + rightPointer := !isReference(ft) + if dc != nil { + rightPointer = dc.Results[0].Type.Kind == types.Pointer + } + if leftPointer == rightPointer { + sw.Do("out.$.name$ = in.$.name$.DeepCopy()\n", args) + } else if leftPointer { + sw.Do("x := in.$.name$.DeepCopy()\n", args) + sw.Do("out.$.name$ = = &x\n", args) + } else { + sw.Do("in.$.name$.DeepCopyInto(&out.$.name$)\n", args) + } + case uft.Kind == types.Builtin: + // the initial *out = *in was enough + case uft.Kind == types.Map, uft.Kind == types.Slice, uft.Kind == types.Pointer: + // Fixup non-nil reference-semantic types. + sw.Do("if in.$.name$ != nil {\n", args) + sw.Do("in, out := &in.$.name$, &out.$.name$\n", args) + g.generateFor(ft, sw) + sw.Do("}\n", nil) + case uft.Kind == types.Array: + sw.Do("out.$.name$ = in.$.name$\n", args) + case uft.Kind == types.Struct: + if ft.IsAssignable() { + sw.Do("out.$.name$ = in.$.name$\n", args) + } else { + sw.Do("in.$.name$.DeepCopyInto(&out.$.name$)\n", args) + } + case uft.Kind == types.Interface: + // Note: do not generate code that won't compile as `DeepCopyinterface{}()` is not a valid function + if uft.Name.Name == "interface{}" { + klog.Fatalf("DeepCopy of %q is unsupported. Instead, use named interfaces with DeepCopy as one of the methods.", uft.Name.Name) + } + sw.Do("if in.$.name$ != nil {\n", args) + // Note: if t.Elem has been an alias "J" of an interface "I" in Go, we will see it + // as kind Interface of name "J" here, i.e. generate val.DeepCopyJ(). The golang + // parser does not give us the underlying interface name. So we cannot do any better. + sw.Do(fmt.Sprintf("out.$.name$ = in.$.name$.DeepCopy%s()\n", uft.Name.Name), args) + sw.Do("}\n", nil) + default: + klog.Fatalf("Hit an unsupported type '%v' for '%v', from %v.%v", uft, ft, t, m.Name) + } + } +} + +// doPointer generates code for a pointer or an alias to a pointer. The generated code is +// is the same for both cases, i.e. it's the code for the underlying type. +func (g *genDeepCopy) doPointer(t *types.Type, sw *generator.SnippetWriter) { + ut := underlyingType(t) + uet := underlyingType(ut.Elem) + + dc, dci := deepCopyMethodOrDie(ut.Elem), deepCopyIntoMethodOrDie(ut.Elem) + switch { + case dc != nil || dci != nil: + rightPointer := !isReference(ut.Elem) + if dc != nil { + rightPointer = dc.Results[0].Type.Kind == types.Pointer + } + if rightPointer { + sw.Do("*out = (*in).DeepCopy()\n", nil) + } else { + sw.Do("x := (*in).DeepCopy()\n", nil) + sw.Do("*out = &x\n", nil) + } + case uet.IsAssignable(): + sw.Do("*out = new($.Elem|raw$)\n", ut) + sw.Do("**out = **in", nil) + case uet.Kind == types.Map, uet.Kind == types.Slice, uet.Kind == types.Pointer: + sw.Do("*out = new($.Elem|raw$)\n", ut) + sw.Do("if **in != nil {\n", nil) + sw.Do("in, out := *in, *out\n", nil) + g.generateFor(uet, sw) + sw.Do("}\n", nil) + case uet.Kind == types.Struct: + sw.Do("*out = new($.Elem|raw$)\n", ut) + sw.Do("(*in).DeepCopyInto(*out)\n", nil) + default: + klog.Fatalf("Hit an unsupported type %v for %v", uet, t) + } +} diff --git a/code-generator/cmd/deepcopy-gen/generators/deepcopy_test.go b/code-generator/cmd/deepcopy-gen/generators/deepcopy_test.go new file mode 100644 index 000000000..f1c3427db --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/generators/deepcopy_test.go @@ -0,0 +1,696 @@ +/* +Copyright 2016 The Kubernetes 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 ( + "reflect" + "testing" + + "k8s.io/gengo/v2/types" +) + +func Test_deepCopyMethod(t *testing.T) { + testCases := []struct { + typ types.Type + expect bool + error bool + }{ + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + // No DeepCopy method. + Methods: map[string]*types.Type{}, + }, + expect: false, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // No DeepCopy method. + "method": { + Name: types.Name{Package: "pkgname", Name: "func()"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.ParamResult{}, + Results: []*types.ParamResult{}, + }, + }, + }, + }, + expect: false, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (no result). + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func()"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.ParamResult{}, + Results: []*types.ParamResult{}, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (wrong result). + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() int"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.ParamResult{}, + Results: []*types.ParamResult{ + { + Type: &types.Type{Name: types.Name{Name: "int"}, Kind: types.Builtin}, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature with pointer receiver, but non-pointer result. + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.ParamResult{}, + Results: []*types.ParamResult{ + { + Type: &types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + }, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature with non-pointer receiver, but pointer result. + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + Parameters: []*types.ParamResult{}, + Results: []*types.ParamResult{ + { + Type: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Correct signature with non-pointer receiver. + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + Parameters: []*types.ParamResult{}, + Results: []*types.ParamResult{ + { + Type: &types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + }, + }, + }, + }, + }, + }, + }, + expect: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Correct signature with pointer receiver. + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() pkgname.typename"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.ParamResult{}, + Results: []*types.ParamResult{ + { + Type: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + }, + }, + }, + }, + }, + }, + expect: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (has params). + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func(int) pkgname.typename"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.ParamResult{ + { + Type: &types.Type{ + Name: types.Name{Name: "int"}, + Kind: types.Builtin, + }, + }, + }, + Results: []*types.ParamResult{ + { + Type: &types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + }, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (extra results). + "DeepCopy": { + Name: types.Name{Package: "pkgname", Name: "func() (pkgname.typename, int)"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.ParamResult{}, + Results: []*types.ParamResult{ + { + Type: &types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + }, + }, + { + Type: &types.Type{ + Name: types.Name{Name: "int"}, + Kind: types.Builtin, + }, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + } + + for i, tc := range testCases { + r, err := deepCopyMethod(&tc.typ) + if tc.error && err == nil { + t.Errorf("case[%d]: expected an error, got none", i) + } else if !tc.error && err != nil { + t.Errorf("case[%d]: expected no error, got: %v", i, err) + } else if !tc.error && (r != nil) != tc.expect { + t.Errorf("case[%d]: expected result %v, got: %v", i, tc.expect, r) + } + } +} + +func Test_deepCopyIntoMethod(t *testing.T) { + testCases := []struct { + typ types.Type + expect bool + error bool + }{ + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + // No DeepCopyInto method. + Methods: map[string]*types.Type{}, + }, + expect: false, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // No DeepCopyInto method. + "method": { + Name: types.Name{Package: "pkgname", Name: "func()"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.ParamResult{}, + Results: []*types.ParamResult{}, + }, + }, + }, + }, + expect: false, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (no parameter). + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func()"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.ParamResult{}, + Results: []*types.ParamResult{}, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (unexpected result). + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename) int"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.ParamResult{ + { + Type: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + }, + }, + Results: []*types.ParamResult{ + { + Type: &types.Type{ + Name: types.Name{Name: "int"}, + Kind: types.Builtin, + }, + }, + }, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (non-pointer parameter, pointer receiver). + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func(pkgname.typename)"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.ParamResult{ + { + Type: &types.Type{ + Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + }, + Results: []*types.ParamResult{}, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Wrong signature (non-pointer parameter, non-pointer receiver). + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func(pkgname.typename)"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + Parameters: []*types.ParamResult{ + { + + Type: &types.Type{ + Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + }, + Results: []*types.ParamResult{}, + }, + }, + }, + }, + expect: false, + error: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Correct signature with non-pointer receiver. + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename)"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + Parameters: []*types.ParamResult{ + { + Type: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + }, + }, + Results: []*types.ParamResult{}, + }, + }, + }, + }, + expect: true, + }, + { + typ: types.Type{ + Name: types.Name{Package: "pkgname", Name: "typename"}, + Kind: types.Builtin, + Methods: map[string]*types.Type{ + // Correct signature with pointer receiver. + "DeepCopyInto": { + Name: types.Name{Package: "pkgname", Name: "func(*pkgname.typename)"}, + Kind: types.Func, + Signature: &types.Signature{ + Receiver: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + Parameters: []*types.ParamResult{ + { + Type: &types.Type{ + Kind: types.Pointer, + Elem: &types.Type{Kind: types.Struct, Name: types.Name{Package: "pkgname", Name: "typename"}}, + }, + }, + }, + Results: []*types.ParamResult{}, + }, + }, + }, + }, + expect: true, + }, + } + + for i, tc := range testCases { + r, err := deepCopyIntoMethod(&tc.typ) + if tc.error && err == nil { + t.Errorf("case[%d]: expected an error, got none", i) + } else if !tc.error && err != nil { + t.Errorf("case[%d]: expected no error, got: %v", i, err) + } else if !tc.error && (r != nil) != tc.expect { + t.Errorf("case[%d]: expected result %v, got: %v", i, tc.expect, r) + } + } +} + +func Test_extractTagParams(t *testing.T) { + testCases := []struct { + comments []string + expect *enabledTagValue + }{ + { + comments: []string{ + "Human comment", + }, + expect: nil, + }, + { + comments: []string{ + "Human comment", + "+k8s:deepcopy-gen", + }, + expect: &enabledTagValue{ + value: "", + register: false, + }, + }, + { + comments: []string{ + "Human comment", + "+k8s:deepcopy-gen=package", + }, + expect: &enabledTagValue{ + value: "package", + register: false, + }, + }, + { + comments: []string{ + "Human comment", + "+k8s:deepcopy-gen=package,register", + }, + expect: &enabledTagValue{ + value: "package", + register: true, + }, + }, + { + comments: []string{ + "Human comment", + "+k8s:deepcopy-gen=package,register=true", + }, + expect: &enabledTagValue{ + value: "package", + register: true, + }, + }, + { + comments: []string{ + "Human comment", + "+k8s:deepcopy-gen=package,register=false", + }, + expect: &enabledTagValue{ + value: "package", + register: false, + }, + }, + } + + for i, tc := range testCases { + r := extractEnabledTag(tc.comments) + if r == nil && tc.expect != nil { + t.Errorf("case[%d]: expected non-nil", i) + } + if r != nil && tc.expect == nil { + t.Errorf("case[%d]: expected nil, got %v", i, *r) + } + if r != nil && *r != *tc.expect { + t.Errorf("case[%d]: expected %v, got %v", i, *tc.expect, *r) + } + } +} + +func Test_extractInterfacesTag(t *testing.T) { + testCases := []struct { + comments, secondComments []string + expect []string + }{ + { + comments: []string{}, + expect: nil, + }, + { + comments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + }, + expect: []string{ + "k8s.io/kubernetes/runtime.Object", + }, + }, + { + comments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.List", + }, + expect: []string{ + "k8s.io/kubernetes/runtime.Object", + "k8s.io/kubernetes/runtime.List", + }, + }, + { + comments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + }, + expect: []string{ + "k8s.io/kubernetes/runtime.Object", + "k8s.io/kubernetes/runtime.Object", + }, + }, + { + secondComments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + }, + expect: []string{ + "k8s.io/kubernetes/runtime.Object", + }, + }, + { + comments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + }, + secondComments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.List", + }, + expect: []string{ + "k8s.io/kubernetes/runtime.List", + "k8s.io/kubernetes/runtime.Object", + }, + }, + { + comments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + }, + secondComments: []string{ + "+k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object", + }, + expect: []string{ + "k8s.io/kubernetes/runtime.Object", + "k8s.io/kubernetes/runtime.Object", + }, + }, + } + + for i, tc := range testCases { + typ := &types.Type{ + CommentLines: tc.comments, + SecondClosestCommentLines: tc.secondComments, + } + r := extractInterfacesTag(typ) + if r == nil && tc.expect != nil { + t.Errorf("case[%d]: expected non-nil", i) + } + if r != nil && tc.expect == nil { + t.Errorf("case[%d]: expected nil, got %v", i, r) + } + if r != nil && !reflect.DeepEqual(r, tc.expect) { + t.Errorf("case[%d]: expected %v, got %v", i, tc.expect, r) + } + } +} diff --git a/code-generator/cmd/deepcopy-gen/main.go b/code-generator/cmd/deepcopy-gen/main.go new file mode 100644 index 000000000..aaa3155a0 --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/main.go @@ -0,0 +1,110 @@ +/* +Copyright 2015 The Kubernetes 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. +*/ + +// deepcopy-gen is a tool for auto-generating DeepCopy functions. +// +// Given a list of input directories, it will generate DeepCopy and +// DeepCopyInto methods that efficiently perform a full deep-copy of each type. +// If these methods already exist (are predefined by the developer), they are +// used instead of generating new ones. Generated code will use standard value +// assignment whenever possible. If that is not possible it will try to call +// its own generated copy function for the type. Failing that, it will fall +// back on `conversion.Cloner.DeepCopy(val)` to make the copy. The resulting +// file will be stored in the same directory as the processed source package. +// +// If interfaces are referenced in types, it is expected that corresponding +// DeepCopyInterfaceName methods exist, e.g. DeepCopyObject for runtime.Object. +// These can be predefined by the developer or generated through tags, see +// below. They must be added to the interfaces themselves manually, e.g. +// +// type Object interface { +// ... +// DeepCopyObject() Object +// } +// +// Generation is governed by comment tags in the source. Any package may +// request DeepCopy generation by including a comment in the file-comments of +// one file, of the form: +// +// // +k8s:deepcopy-gen=package +// +// DeepCopy functions can be generated for individual types, rather than the +// entire package by specifying a comment on the type definition of the form: +// +// // +k8s:deepcopy-gen=true +// +// When generating for a whole package, individual types may opt out of +// DeepCopy generation by specifying a comment on the type definition of the +// form: +// +// // +k8s:deepcopy-gen=false +// +// Additional DeepCopyInterfaceName methods can be generated by specifying a +// comment on the type definition of the form: +// +// // +k8s:deepcopy-gen:interfaces=k8s.io/kubernetes/runtime.Object,k8s.io/kubernetes/runtime.List +// +// This leads to the generation of DeepCopyObject and DeepCopyList with the given +// interfaces as return types. We say that the tagged type implements deepcopy for the +// interfaces. +// +// The deepcopy funcs for interfaces using "+k8s:deepcopy-gen:interfaces" use the pointer +// of the type as receiver. For those special cases where the non-pointer object should +// implement the interface, this can be done with: +// +// // +k8s:deepcopy-gen:nonpointer-interfaces=true +package main + +import ( + "flag" + + "github.com/spf13/pflag" + "k8s.io/code-generator/cmd/deepcopy-gen/args" + "k8s.io/code-generator/cmd/deepcopy-gen/generators" + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/klog/v2" +) + +func main() { + klog.InitFlags(nil) + args := args.New() + + args.AddFlags(pflag.CommandLine) + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + if err := args.Validate(); err != nil { + klog.Fatalf("Error: %v", err) + } + + myTargets := func(context *generator.Context) []generator.Target { + return generators.GetTargets(context, args) + } + + // Run it. + if err := gengo.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + myTargets, + gengo.StdBuildTag, + pflag.Args(), + ); err != nil { + klog.Fatalf("Error: %v", err) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/aliases/doc.go b/code-generator/cmd/deepcopy-gen/output_tests/aliases/doc.go new file mode 100644 index 000000000..d007d34f7 --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/aliases/doc.go @@ -0,0 +1,89 @@ +/* +Copyright 2018 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package + +// This is a test package. +package aliases + +// Note: the following AliasInterface and AliasAliasInterface +k8s:deepcopy-gen:interfaces tags +// are necessary because Golang flattens interface alias in the type system. I.e. an alias J of +// an interface I is actually equivalent to I. So support deepcopies of those aliases, we have +// to implement all aliases of that interface. + +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/aliases.Interface +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/aliases.AliasInterface +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/aliases.AliasAliasInterface +type Foo struct { + X int +} + +type Interface interface { + DeepCopyInterface() Interface + DeepCopyAliasInterface() AliasInterface + DeepCopyAliasAliasInterface() AliasAliasInterface +} + +type Builtin int +type Slice []int +type Pointer *int +type PointerAlias *Builtin +type Struct Foo +type Map map[string]int + +type FooAlias Foo +type FooSlice []Foo +type FooPointer *Foo +type FooMap map[string]Foo + +type AliasBuiltin Builtin +type AliasSlice Slice +type AliasPointer Pointer +type AliasStruct Struct +type AliasMap Map + +type AliasInterface Interface +type AliasAliasInterface AliasInterface +type AliasInterfaceMap map[string]AliasInterface +type AliasInterfaceSlice []AliasInterface + +// Aliases +type Ttest struct { + Builtin Builtin + Slice Slice + Pointer Pointer + PointerAlias PointerAlias + Struct Struct + Map Map + SliceSlice []Slice + MapSlice map[string]Slice + + FooAlias FooAlias + FooSlice FooSlice + FooPointer FooPointer + FooMap FooMap + + AliasBuiltin AliasBuiltin + AliasSlice AliasSlice + AliasPointer AliasPointer + AliasStruct AliasStruct + AliasMap AliasMap + + AliasInterface AliasInterface + AliasAliasInterface AliasAliasInterface + AliasInterfaceMap AliasInterfaceMap + AliasInterfaceSlice AliasInterfaceSlice +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/aliases/zz_generated.deepcopy.go b/code-generator/cmd/deepcopy-gen/output_tests/aliases/zz_generated.deepcopy.go new file mode 100644 index 000000000..e7c6827f0 --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/aliases/zz_generated.deepcopy.go @@ -0,0 +1,413 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package aliases + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in AliasInterfaceMap) DeepCopyInto(out *AliasInterfaceMap) { + { + in := &in + *out = make(AliasInterfaceMap, len(*in)) + for key, val := range *in { + if val == nil { + (*out)[key] = nil + } else { + (*out)[key] = val.DeepCopyAliasInterface() + } + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AliasInterfaceMap. +func (in AliasInterfaceMap) DeepCopy() AliasInterfaceMap { + if in == nil { + return nil + } + out := new(AliasInterfaceMap) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in AliasInterfaceSlice) DeepCopyInto(out *AliasInterfaceSlice) { + { + in := &in + *out = make(AliasInterfaceSlice, len(*in)) + for i := range *in { + if (*in)[i] != nil { + (*out)[i] = (*in)[i].DeepCopyAliasInterface() + } + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AliasInterfaceSlice. +func (in AliasInterfaceSlice) DeepCopy() AliasInterfaceSlice { + if in == nil { + return nil + } + out := new(AliasInterfaceSlice) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in AliasMap) DeepCopyInto(out *AliasMap) { + { + in := &in + *out = make(AliasMap, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AliasMap. +func (in AliasMap) DeepCopy() AliasMap { + if in == nil { + return nil + } + out := new(AliasMap) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in AliasSlice) DeepCopyInto(out *AliasSlice) { + { + in := &in + *out = make(AliasSlice, len(*in)) + copy(*out, *in) + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AliasSlice. +func (in AliasSlice) DeepCopy() AliasSlice { + if in == nil { + return nil + } + out := new(AliasSlice) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AliasStruct) DeepCopyInto(out *AliasStruct) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AliasStruct. +func (in *AliasStruct) DeepCopy() *AliasStruct { + if in == nil { + return nil + } + out := new(AliasStruct) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Foo) DeepCopyInto(out *Foo) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Foo. +func (in *Foo) DeepCopy() *Foo { + if in == nil { + return nil + } + out := new(Foo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyAliasAliasInterface is an autogenerated deepcopy function, copying the receiver, creating a new AliasAliasInterface. +func (in *Foo) DeepCopyAliasAliasInterface() AliasAliasInterface { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyAliasInterface is an autogenerated deepcopy function, copying the receiver, creating a new AliasInterface. +func (in *Foo) DeepCopyAliasInterface() AliasInterface { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInterface is an autogenerated deepcopy function, copying the receiver, creating a new Interface. +func (in *Foo) DeepCopyInterface() Interface { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FooAlias) DeepCopyInto(out *FooAlias) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooAlias. +func (in *FooAlias) DeepCopy() *FooAlias { + if in == nil { + return nil + } + out := new(FooAlias) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in FooMap) DeepCopyInto(out *FooMap) { + { + in := &in + *out = make(FooMap, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooMap. +func (in FooMap) DeepCopy() FooMap { + if in == nil { + return nil + } + out := new(FooMap) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in FooSlice) DeepCopyInto(out *FooSlice) { + { + in := &in + *out = make(FooSlice, len(*in)) + copy(*out, *in) + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooSlice. +func (in FooSlice) DeepCopy() FooSlice { + if in == nil { + return nil + } + out := new(FooSlice) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in Map) DeepCopyInto(out *Map) { + { + in := &in + *out = make(Map, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Map. +func (in Map) DeepCopy() Map { + if in == nil { + return nil + } + out := new(Map) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in Slice) DeepCopyInto(out *Slice) { + { + in := &in + *out = make(Slice, len(*in)) + copy(*out, *in) + return + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Slice. +func (in Slice) DeepCopy() Slice { + if in == nil { + return nil + } + out := new(Slice) + in.DeepCopyInto(out) + return *out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Struct) DeepCopyInto(out *Struct) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Struct. +func (in *Struct) DeepCopy() *Struct { + if in == nil { + return nil + } + out := new(Struct) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Ttest) DeepCopyInto(out *Ttest) { + *out = *in + if in.Slice != nil { + in, out := &in.Slice, &out.Slice + *out = make(Slice, len(*in)) + copy(*out, *in) + } + if in.Pointer != nil { + in, out := &in.Pointer, &out.Pointer + *out = new(int) + **out = **in + } + if in.PointerAlias != nil { + in, out := &in.PointerAlias, &out.PointerAlias + *out = new(Builtin) + **out = **in + } + out.Struct = in.Struct + if in.Map != nil { + in, out := &in.Map, &out.Map + *out = make(Map, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.SliceSlice != nil { + in, out := &in.SliceSlice, &out.SliceSlice + *out = make([]Slice, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make(Slice, len(*in)) + copy(*out, *in) + } + } + } + if in.MapSlice != nil { + in, out := &in.MapSlice, &out.MapSlice + *out = make(map[string]Slice, len(*in)) + for key, val := range *in { + var outVal []int + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make(Slice, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } + out.FooAlias = in.FooAlias + if in.FooSlice != nil { + in, out := &in.FooSlice, &out.FooSlice + *out = make(FooSlice, len(*in)) + copy(*out, *in) + } + if in.FooPointer != nil { + in, out := &in.FooPointer, &out.FooPointer + *out = new(Foo) + **out = **in + } + if in.FooMap != nil { + in, out := &in.FooMap, &out.FooMap + *out = make(FooMap, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.AliasSlice != nil { + in, out := &in.AliasSlice, &out.AliasSlice + *out = make(AliasSlice, len(*in)) + copy(*out, *in) + } + if in.AliasPointer != nil { + in, out := &in.AliasPointer, &out.AliasPointer + *out = new(int) + **out = **in + } + out.AliasStruct = in.AliasStruct + if in.AliasMap != nil { + in, out := &in.AliasMap, &out.AliasMap + *out = make(AliasMap, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.AliasInterface != nil { + out.AliasInterface = in.AliasInterface.DeepCopyAliasInterface() + } + if in.AliasAliasInterface != nil { + out.AliasAliasInterface = in.AliasAliasInterface.DeepCopyAliasAliasInterface() + } + if in.AliasInterfaceMap != nil { + in, out := &in.AliasInterfaceMap, &out.AliasInterfaceMap + *out = make(AliasInterfaceMap, len(*in)) + for key, val := range *in { + if val == nil { + (*out)[key] = nil + } else { + (*out)[key] = val.DeepCopyAliasInterface() + } + } + } + if in.AliasInterfaceSlice != nil { + in, out := &in.AliasInterfaceSlice, &out.AliasInterfaceSlice + *out = make(AliasInterfaceSlice, len(*in)) + for i := range *in { + if (*in)[i] != nil { + (*out)[i] = (*in)[i].DeepCopyAliasInterface() + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest. +func (in *Ttest) DeepCopy() *Ttest { + if in == nil { + return nil + } + out := new(Ttest) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/builtins/doc.go b/code-generator/cmd/deepcopy-gen/output_tests/builtins/doc.go new file mode 100644 index 000000000..34097c84d --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/builtins/doc.go @@ -0,0 +1,35 @@ +/* +Copyright 2016 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package + +// This is a test package. +package builtins + +type Ttest struct { + Byte byte + // Int8 int8 // TODO: int8 becomes byte in SnippetWriter + Int16 int16 + Int32 int32 + Int64 int64 + Uint8 uint8 + Uint16 uint16 + Uint32 uint32 + Uint64 uint64 + Float32 float32 + Float64 float64 + String string +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/builtins/zz_generated.deepcopy.go b/code-generator/cmd/deepcopy-gen/output_tests/builtins/zz_generated.deepcopy.go new file mode 100644 index 000000000..afc71ffb0 --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/builtins/zz_generated.deepcopy.go @@ -0,0 +1,38 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package builtins + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Ttest) DeepCopyInto(out *Ttest) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest. +func (in *Ttest) DeepCopy() *Ttest { + if in == nil { + return nil + } + out := new(Ttest) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/generate.go b/code-generator/cmd/deepcopy-gen/output_tests/generate.go new file mode 100644 index 000000000..9ae99ee9b --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/generate.go @@ -0,0 +1,18 @@ +/* +Copyright 2024 The Kubernetes 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. +*/ + +//go:generate go run k8s.io/code-generator/cmd/deepcopy-gen --output-file zz_generated.deepcopy.go --go-header-file=../../../examples/hack/boilerplate.go.txt k8s.io/code-generator/cmd/deepcopy-gen/output_tests/... +package outputtests diff --git a/code-generator/cmd/deepcopy-gen/output_tests/interface_fuzzer.go b/code-generator/cmd/deepcopy-gen/output_tests/interface_fuzzer.go new file mode 100644 index 000000000..11fdb84bf --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/interface_fuzzer.go @@ -0,0 +1,131 @@ +/* +Copyright 2018 The Kubernetes 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 outputtests + +import ( + "github.com/google/gofuzz" + + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/aliases" + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/interfaces" +) + +// interfaceFuzzers contains fuzzer that set all interface to nil because our +// JSON deepcopy does not work with it. +// TODO: test also interface deepcopy +var interfaceFuzzers = []interface{}{ + func(s *aliases.AliasAliasInterface, c fuzz.Continue) { + if c.RandBool() { + *s = nil + } else { + *s = &aliasAliasInterfaceInstance{X: c.Int()} + } + }, + func(s *aliases.AliasInterface, c fuzz.Continue) { + if c.RandBool() { + *s = nil + } else { + *s = &aliasAliasInterfaceInstance{X: c.Int()} + } + }, + func(s *aliases.Interface, c fuzz.Continue) { + if c.RandBool() { + *s = nil + } else { + *s = &aliasAliasInterfaceInstance{X: c.Int()} + } + }, + func(s *aliases.AliasInterfaceMap, c fuzz.Continue) { + if c.RandBool() { + *s = nil + } else { + *s = make(aliases.AliasInterfaceMap) + for i := 0; i < c.Intn(3); i++ { + if c.RandBool() { + (*s)[c.RandString()] = nil + } else { + (*s)[c.RandString()] = &aliasAliasInterfaceInstance{X: c.Int()} + } + } + } + + }, + func(s *aliases.AliasInterfaceSlice, c fuzz.Continue) { + if c.RandBool() { + *s = nil + } else { + *s = make(aliases.AliasInterfaceSlice, 0) + for i := 0; i < c.Intn(3); i++ { + if c.RandBool() { + *s = append(*s, nil) + } else { + *s = append(*s, &aliasAliasInterfaceInstance{X: c.Int()}) + } + } + } + }, + func(s *interfaces.Inner, c fuzz.Continue) { + if c.RandBool() { + *s = nil + } else { + *s = &interfacesInnerInstance{X: c.Float64()} + } + }, +} + +type aliasAliasInterfaceInstance struct { + X int +} + +func (i *aliasAliasInterfaceInstance) DeepCopyInterface() aliases.Interface { + if i == nil { + return nil + } + + return &aliasAliasInterfaceInstance{X: i.X} +} + +func (i *aliasAliasInterfaceInstance) DeepCopyAliasInterface() aliases.AliasInterface { + if i == nil { + return nil + } + + return &aliasAliasInterfaceInstance{X: i.X} +} + +func (i *aliasAliasInterfaceInstance) DeepCopyAliasAliasInterface() aliases.AliasAliasInterface { + if i == nil { + return nil + } + + return &aliasAliasInterfaceInstance{X: i.X} +} + +type interfacesInnerInstance struct { + X float64 +} + +func (i *interfacesInnerInstance) DeepCopyInner() interfaces.Inner { + if i == nil { + return nil + } + + return &interfacesInnerInstance{X: i.X} +} + +func (i *interfacesInnerInstance) Function() float64 { + return i.X +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/interfaces/doc.go b/code-generator/cmd/deepcopy-gen/output_tests/interfaces/doc.go new file mode 100644 index 000000000..2d01f2e60 --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/interfaces/doc.go @@ -0,0 +1,29 @@ +/* +Copyright 2017 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package + +// This is a test package. +package interfaces + +type Inner interface { + Function() float64 + DeepCopyInner() Inner +} + +type Ttest struct { + I []Inner +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/interfaces/zz_generated.deepcopy.go b/code-generator/cmd/deepcopy-gen/output_tests/interfaces/zz_generated.deepcopy.go new file mode 100644 index 000000000..abaa51b16 --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/interfaces/zz_generated.deepcopy.go @@ -0,0 +1,47 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package interfaces + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Ttest) DeepCopyInto(out *Ttest) { + *out = *in + if in.I != nil { + in, out := &in.I, &out.I + *out = make([]Inner, len(*in)) + for i := range *in { + if (*in)[i] != nil { + (*out)[i] = (*in)[i].DeepCopyInner() + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest. +func (in *Ttest) DeepCopy() *Ttest { + if in == nil { + return nil + } + out := new(Ttest) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/maps/doc.go b/code-generator/cmd/deepcopy-gen/output_tests/maps/doc.go new file mode 100644 index 000000000..01871e44d --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/maps/doc.go @@ -0,0 +1,43 @@ +/* +Copyright 2016 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package + +// This is a test package. +package maps + +type Ttest struct { + Byte map[string]byte + // Int8 map[string]int8 //TODO: int8 becomes byte in SnippetWriter + Int16 map[string]int16 + Int32 map[string]int32 + Int64 map[string]int64 + Uint8 map[string]uint8 + Uint16 map[string]uint16 + Uint32 map[string]uint32 + Uint64 map[string]uint64 + Float32 map[string]float32 + Float64 map[string]float64 + String map[string]string + StringPtr map[string]*string + StringPtrPtr map[string]**string + Map map[string]map[string]string + MapPtr map[string]*map[string]string + Slice map[string][]string + SlicePtr map[string]*[]string + Struct map[string]Ttest + StructPtr map[string]*Ttest +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/maps/zz_generated.deepcopy.go b/code-generator/cmd/deepcopy-gen/output_tests/maps/zz_generated.deepcopy.go new file mode 100644 index 000000000..77103245a --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/maps/zz_generated.deepcopy.go @@ -0,0 +1,243 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package maps + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Ttest) DeepCopyInto(out *Ttest) { + *out = *in + if in.Byte != nil { + in, out := &in.Byte, &out.Byte + *out = make(map[string]byte, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Int16 != nil { + in, out := &in.Int16, &out.Int16 + *out = make(map[string]int16, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Int32 != nil { + in, out := &in.Int32, &out.Int32 + *out = make(map[string]int32, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Int64 != nil { + in, out := &in.Int64, &out.Int64 + *out = make(map[string]int64, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Uint8 != nil { + in, out := &in.Uint8, &out.Uint8 + *out = make(map[string]byte, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Uint16 != nil { + in, out := &in.Uint16, &out.Uint16 + *out = make(map[string]uint16, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Uint32 != nil { + in, out := &in.Uint32, &out.Uint32 + *out = make(map[string]uint32, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Uint64 != nil { + in, out := &in.Uint64, &out.Uint64 + *out = make(map[string]uint64, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Float32 != nil { + in, out := &in.Float32, &out.Float32 + *out = make(map[string]float32, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Float64 != nil { + in, out := &in.Float64, &out.Float64 + *out = make(map[string]float64, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.String != nil { + in, out := &in.String, &out.String + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.StringPtr != nil { + in, out := &in.StringPtr, &out.StringPtr + *out = make(map[string]*string, len(*in)) + for key, val := range *in { + var outVal *string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(string) + **out = **in + } + (*out)[key] = outVal + } + } + if in.StringPtrPtr != nil { + in, out := &in.StringPtrPtr, &out.StringPtrPtr + *out = make(map[string]**string, len(*in)) + for key, val := range *in { + var outVal **string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(*string) + if **in != nil { + in, out := *in, *out + *out = new(string) + **out = **in + } + } + (*out)[key] = outVal + } + } + if in.Map != nil { + in, out := &in.Map, &out.Map + *out = make(map[string]map[string]string, len(*in)) + for key, val := range *in { + var outVal map[string]string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + (*out)[key] = outVal + } + } + if in.MapPtr != nil { + in, out := &in.MapPtr, &out.MapPtr + *out = make(map[string]*map[string]string, len(*in)) + for key, val := range *in { + var outVal *map[string]string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(map[string]string) + if **in != nil { + in, out := *in, *out + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + } + (*out)[key] = outVal + } + } + if in.Slice != nil { + in, out := &in.Slice, &out.Slice + *out = make(map[string][]string, len(*in)) + for key, val := range *in { + var outVal []string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = make([]string, len(*in)) + copy(*out, *in) + } + (*out)[key] = outVal + } + } + if in.SlicePtr != nil { + in, out := &in.SlicePtr, &out.SlicePtr + *out = make(map[string]*[]string, len(*in)) + for key, val := range *in { + var outVal *[]string + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new([]string) + if **in != nil { + in, out := *in, *out + *out = make([]string, len(*in)) + copy(*out, *in) + } + } + (*out)[key] = outVal + } + } + if in.Struct != nil { + in, out := &in.Struct, &out.Struct + *out = make(map[string]Ttest, len(*in)) + for key, val := range *in { + (*out)[key] = *val.DeepCopy() + } + } + if in.StructPtr != nil { + in, out := &in.StructPtr, &out.StructPtr + *out = make(map[string]*Ttest, len(*in)) + for key, val := range *in { + var outVal *Ttest + if val == nil { + (*out)[key] = nil + } else { + in, out := &val, &outVal + *out = new(Ttest) + (*in).DeepCopyInto(*out) + } + (*out)[key] = outVal + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest. +func (in *Ttest) DeepCopy() *Ttest { + if in == nil { + return nil + } + out := new(Ttest) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/otherpkg/interfaces.go b/code-generator/cmd/deepcopy-gen/output_tests/otherpkg/interfaces.go new file mode 100644 index 000000000..980fab013 --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/otherpkg/interfaces.go @@ -0,0 +1,25 @@ +/* +Copyright 2017 The Kubernetes 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 otherpkg + +type Object interface { + DeepCopyObject() Object +} + +type List interface { + DeepCopyList() List +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/output_test.go b/code-generator/cmd/deepcopy-gen/output_tests/output_test.go new file mode 100644 index 000000000..6b8994963 --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/output_test.go @@ -0,0 +1,173 @@ +/* +Copyright 2024 The Kubernetes 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 outputtests + +import ( + "fmt" + "reflect" + "testing" + + "github.com/davecgh/go-spew/spew" + "github.com/google/gofuzz" + + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/aliases" + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/builtins" + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/interfaces" + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/maps" + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/pointer" + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/slices" + "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/structs" +) + +func TestWithValueFuzzer(t *testing.T) { + tests := []interface{}{ + aliases.Ttest{}, + builtins.Ttest{}, + interfaces.Ttest{}, + maps.Ttest{}, + pointer.Ttest{}, + slices.Ttest{}, + structs.Ttest{}, + } + + fuzzer := fuzz.New() + fuzzer.NilChance(0.5) + fuzzer.NumElements(0, 2) + fuzzer.Funcs(interfaceFuzzers...) + + for _, test := range tests { + t.Run(fmt.Sprintf("%T", test), func(t *testing.T) { + N := 1000 + for i := 0; i < N; i++ { + original := reflect.New(reflect.TypeOf(test)).Interface() + + fuzzer.Fuzz(original) + + reflectCopy := ReflectDeepCopy(original) + + if !reflect.DeepEqual(original, reflectCopy) { + t.Errorf("original and reflectCopy are different:\n\n original = %s\n\n jsonCopy = %s", spew.Sdump(original), spew.Sdump(reflectCopy)) + } + + deepCopy := reflect.ValueOf(original).MethodByName("DeepCopy").Call(nil)[0].Interface() + + if !reflect.DeepEqual(original, deepCopy) { + t.Fatalf("original and deepCopy are different:\n\n original = %s\n\n deepCopy() = %s", spew.Sdump(original), spew.Sdump(deepCopy)) + } + + ValueFuzz(original) + + if !reflect.DeepEqual(reflectCopy, deepCopy) { + t.Fatalf("reflectCopy and deepCopy are different:\n\n origin = %s\n\n jsonCopy() = %s", spew.Sdump(original), spew.Sdump(deepCopy)) + } + } + }) + } +} + +func BenchmarkReflectDeepCopy(b *testing.B) { + fourtytwo := "fourtytwo" + fourtytwoPtr := &fourtytwo + var nilMap map[string]string + var nilSlice []string + mapPtr := &map[string]string{"0": "fourtytwo", "1": "fourtytwo"} + slicePtr := &[]string{"fourtytwo", "fourtytwo", "fourtytwo"} + structPtr := &pointer.Ttest{ + Builtin: &fourtytwo, + Ptr: &fourtytwoPtr, + } + + tests := []interface{}{ + maps.Ttest{ + Byte: map[string]byte{"0": 42, "1": 42, "3": 42}, + Int16: map[string]int16{"0": 42, "1": 42, "3": 42}, + Int32: map[string]int32{"0": 42, "1": 42, "3": 42}, + Int64: map[string]int64{"0": 42, "1": 42, "3": 42}, + Uint8: map[string]uint8{"0": 42, "1": 42, "3": 42}, + Uint16: map[string]uint16{"0": 42, "1": 42, "3": 42}, + Uint32: map[string]uint32{"0": 42, "1": 42, "3": 42}, + Uint64: map[string]uint64{"0": 42, "1": 42, "3": 42}, + Float32: map[string]float32{"0": 42.0, "1": 42.0, "3": 42.0}, + Float64: map[string]float64{"0": 42, "1": 42, "3": 42}, + String: map[string]string{"0": "fourtytwo", "1": "fourtytwo", "3": "fourtytwo"}, + StringPtr: map[string]*string{"0": &fourtytwo, "1": &fourtytwo, "3": &fourtytwo}, + StringPtrPtr: map[string]**string{"0": &fourtytwoPtr, "1": &fourtytwoPtr, "3": &fourtytwoPtr}, + Map: map[string]map[string]string{"0": nil, "1": {"a": fourtytwo, "b": fourtytwo}, "3": {}}, + MapPtr: map[string]*map[string]string{"0": nil, "1": {"a": fourtytwo, "b": fourtytwo}, "3": &nilMap}, + Slice: map[string][]string{"0": nil, "1": {"a", "b"}, "2": {}}, + SlicePtr: map[string]*[]string{"0": nil, "1": {"a", "b"}, "2": &nilSlice}, + Struct: map[string]maps.Ttest{"0": {}, "1": {Byte: map[string]byte{"0": 42, "1": 42, "3": 42}}}, + StructPtr: map[string]*maps.Ttest{"0": nil, "1": {}, "2": {Byte: map[string]byte{"0": 42, "1": 42, "3": 42}}}, + }, + slices.Ttest{ + Byte: []byte{42, 42, 42}, + Int16: []int16{42, 42, 42}, + Int32: []int32{42, 42, 42}, + Int64: []int64{42, 42, 42}, + Uint8: []uint8{42, 42, 42}, + Uint16: []uint16{42, 42, 42}, + Uint32: []uint32{42, 42, 42}, + Uint64: []uint64{42, 42, 42}, + Float32: []float32{42.0, 42.0, 42.0}, + Float64: []float64{42, 42, 42}, + String: []string{"fourtytwo", "fourtytwo", "fourtytwo"}, + StringPtr: []*string{&fourtytwo, &fourtytwo, &fourtytwo}, + StringPtrPtr: []**string{&fourtytwoPtr, &fourtytwoPtr, &fourtytwoPtr}, + Map: []map[string]string{nil, {"a": fourtytwo, "b": fourtytwo}, {}}, + MapPtr: []*map[string]string{nil, {"a": fourtytwo, "b": fourtytwo}, &nilMap}, + Slice: [][]string{nil, {"a", "b"}, {}}, + SlicePtr: []*[]string{nil, {"a", "b"}, &nilSlice}, + Struct: []slices.Ttest{{}, {Byte: []byte{42, 42, 42}}}, + StructPtr: []*slices.Ttest{nil, {}, {Byte: []byte{42, 42, 42}}}, + }, + pointer.Ttest{ + Builtin: &fourtytwo, + Ptr: &fourtytwoPtr, + Map: &map[string]string{"0": "fourtytwo", "1": "fourtytwo"}, + Slice: &[]string{"fourtytwo", "fourtytwo", "fourtytwo"}, + MapPtr: &mapPtr, + SlicePtr: &slicePtr, + Struct: &pointer.Ttest{ + Builtin: &fourtytwo, + Ptr: &fourtytwoPtr, + }, + StructPtr: &structPtr, + }, + } + + fuzzer := fuzz.New() + fuzzer.NilChance(0.5) + fuzzer.NumElements(0, 2) + fuzzer.Funcs(interfaceFuzzers...) + + for _, test := range tests { + b.Run(fmt.Sprintf("%T", test), func(b *testing.B) { + for i := 0; i < b.N; i++ { + switch t := test.(type) { + case maps.Ttest: + t.DeepCopy() + case slices.Ttest: + t.DeepCopy() + case pointer.Ttest: + t.DeepCopy() + default: + b.Fatalf("missing type case in switch for %T", t) + } + } + }) + } +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/pointer/doc.go b/code-generator/cmd/deepcopy-gen/output_tests/pointer/doc.go new file mode 100644 index 000000000..fd461101b --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/pointer/doc.go @@ -0,0 +1,31 @@ +/* +Copyright 2017 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package + +// This is a test package. +package pointer + +type Ttest struct { + Builtin *string + Ptr **string + Map *map[string]string + Slice *[]string + MapPtr **map[string]string + SlicePtr **[]string + Struct *Ttest + StructPtr **Ttest +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/pointer/zz_generated.deepcopy.go b/code-generator/cmd/deepcopy-gen/output_tests/pointer/zz_generated.deepcopy.go new file mode 100644 index 000000000..ceb9a52dc --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/pointer/zz_generated.deepcopy.go @@ -0,0 +1,114 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package pointer + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Ttest) DeepCopyInto(out *Ttest) { + *out = *in + if in.Builtin != nil { + in, out := &in.Builtin, &out.Builtin + *out = new(string) + **out = **in + } + if in.Ptr != nil { + in, out := &in.Ptr, &out.Ptr + *out = new(*string) + if **in != nil { + in, out := *in, *out + *out = new(string) + **out = **in + } + } + if in.Map != nil { + in, out := &in.Map, &out.Map + *out = new(map[string]string) + if **in != nil { + in, out := *in, *out + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + } + if in.Slice != nil { + in, out := &in.Slice, &out.Slice + *out = new([]string) + if **in != nil { + in, out := *in, *out + *out = make([]string, len(*in)) + copy(*out, *in) + } + } + if in.MapPtr != nil { + in, out := &in.MapPtr, &out.MapPtr + *out = new(*map[string]string) + if **in != nil { + in, out := *in, *out + *out = new(map[string]string) + if **in != nil { + in, out := *in, *out + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + } + } + if in.SlicePtr != nil { + in, out := &in.SlicePtr, &out.SlicePtr + *out = new(*[]string) + if **in != nil { + in, out := *in, *out + *out = new([]string) + if **in != nil { + in, out := *in, *out + *out = make([]string, len(*in)) + copy(*out, *in) + } + } + } + if in.Struct != nil { + in, out := &in.Struct, &out.Struct + *out = new(Ttest) + (*in).DeepCopyInto(*out) + } + if in.StructPtr != nil { + in, out := &in.StructPtr, &out.StructPtr + *out = new(*Ttest) + if **in != nil { + in, out := *in, *out + *out = new(Ttest) + (*in).DeepCopyInto(*out) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest. +func (in *Ttest) DeepCopy() *Ttest { + if in == nil { + return nil + } + out := new(Ttest) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/reflect_deepcopy.go b/code-generator/cmd/deepcopy-gen/output_tests/reflect_deepcopy.go new file mode 100644 index 000000000..ffb3241af --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/reflect_deepcopy.go @@ -0,0 +1,81 @@ +/* +Copyright 2018 The Kubernetes 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 outputtests + +import ( + "fmt" + "reflect" +) + +// ReflectDeepCopy deep copies the object using reflection. +func ReflectDeepCopy(in interface{}) interface{} { + return reflectDeepCopy(reflect.ValueOf(in)).Interface() +} + +func reflectDeepCopy(src reflect.Value) reflect.Value { + switch src.Kind() { + case reflect.Interface, reflect.Ptr, reflect.Map, reflect.Slice: + if src.IsNil() { + return src + } + } + + switch src.Kind() { + case reflect.Chan, reflect.Func, reflect.UnsafePointer, reflect.Uintptr: + panic(fmt.Sprintf("cannot deep copy kind: %s", src.Kind())) + case reflect.Array: + dst := reflect.New(src.Type()) + for i := 0; i < src.Len(); i++ { + dst.Elem().Index(i).Set(reflectDeepCopy(src.Index(i))) + } + return dst.Elem() + case reflect.Interface: + return reflectDeepCopy(src.Elem()) + case reflect.Map: + dst := reflect.MakeMap(src.Type()) + for _, k := range src.MapKeys() { + dst.SetMapIndex(k, reflectDeepCopy(src.MapIndex(k))) + } + return dst + case reflect.Ptr: + dst := reflect.New(src.Type().Elem()) + dst.Elem().Set(reflectDeepCopy(src.Elem())) + return dst + case reflect.Slice: + dst := reflect.MakeSlice(src.Type(), 0, src.Len()) + for i := 0; i < src.Len(); i++ { + dst = reflect.Append(dst, reflectDeepCopy(src.Index(i))) + } + return dst + case reflect.Struct: + dst := reflect.New(src.Type()) + for i := 0; i < src.NumField(); i++ { + if !dst.Elem().Field(i).CanSet() { + // Can't set private fields. At this point, the + // best we can do is a shallow copy. For + // example, time.Time is a value type with + // private members that can be shallow copied. + return src + } + dst.Elem().Field(i).Set(reflectDeepCopy(src.Field(i))) + } + return dst.Elem() + default: + // Value types like numbers, booleans, and strings. + return src + } +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/slices/doc.go b/code-generator/cmd/deepcopy-gen/output_tests/slices/doc.go new file mode 100644 index 000000000..183d73628 --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/slices/doc.go @@ -0,0 +1,43 @@ +/* +Copyright 2016 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package + +// This is a test package. +package slices + +type Ttest struct { + Byte []byte + // Int8 []int8 //TODO: int8 becomes byte in SnippetWriter + Int16 []int16 + Int32 []int32 + Int64 []int64 + Uint8 []uint8 + Uint16 []uint16 + Uint32 []uint32 + Uint64 []uint64 + Float32 []float32 + Float64 []float64 + String []string + StringPtr []*string + StringPtrPtr []**string + Map []map[string]string + MapPtr []*map[string]string + Slice [][]string + SlicePtr []*[]string + Struct []Ttest + StructPtr []*Ttest +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/slices/zz_generated.deepcopy.go b/code-generator/cmd/deepcopy-gen/output_tests/slices/zz_generated.deepcopy.go new file mode 100644 index 000000000..04d4276a9 --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/slices/zz_generated.deepcopy.go @@ -0,0 +1,193 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package slices + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Ttest) DeepCopyInto(out *Ttest) { + *out = *in + if in.Byte != nil { + in, out := &in.Byte, &out.Byte + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.Int16 != nil { + in, out := &in.Int16, &out.Int16 + *out = make([]int16, len(*in)) + copy(*out, *in) + } + if in.Int32 != nil { + in, out := &in.Int32, &out.Int32 + *out = make([]int32, len(*in)) + copy(*out, *in) + } + if in.Int64 != nil { + in, out := &in.Int64, &out.Int64 + *out = make([]int64, len(*in)) + copy(*out, *in) + } + if in.Uint8 != nil { + in, out := &in.Uint8, &out.Uint8 + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.Uint16 != nil { + in, out := &in.Uint16, &out.Uint16 + *out = make([]uint16, len(*in)) + copy(*out, *in) + } + if in.Uint32 != nil { + in, out := &in.Uint32, &out.Uint32 + *out = make([]uint32, len(*in)) + copy(*out, *in) + } + if in.Uint64 != nil { + in, out := &in.Uint64, &out.Uint64 + *out = make([]uint64, len(*in)) + copy(*out, *in) + } + if in.Float32 != nil { + in, out := &in.Float32, &out.Float32 + *out = make([]float32, len(*in)) + copy(*out, *in) + } + if in.Float64 != nil { + in, out := &in.Float64, &out.Float64 + *out = make([]float64, len(*in)) + copy(*out, *in) + } + if in.String != nil { + in, out := &in.String, &out.String + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.StringPtr != nil { + in, out := &in.StringPtr, &out.StringPtr + *out = make([]*string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(string) + **out = **in + } + } + } + if in.StringPtrPtr != nil { + in, out := &in.StringPtrPtr, &out.StringPtrPtr + *out = make([]**string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(*string) + if **in != nil { + in, out := *in, *out + *out = new(string) + **out = **in + } + } + } + } + if in.Map != nil { + in, out := &in.Map, &out.Map + *out = make([]map[string]string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + } + } + if in.MapPtr != nil { + in, out := &in.MapPtr, &out.MapPtr + *out = make([]*map[string]string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(map[string]string) + if **in != nil { + in, out := *in, *out + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + } + } + } + if in.Slice != nil { + in, out := &in.Slice, &out.Slice + *out = make([][]string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make([]string, len(*in)) + copy(*out, *in) + } + } + } + if in.SlicePtr != nil { + in, out := &in.SlicePtr, &out.SlicePtr + *out = make([]*[]string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new([]string) + if **in != nil { + in, out := *in, *out + *out = make([]string, len(*in)) + copy(*out, *in) + } + } + } + } + if in.Struct != nil { + in, out := &in.Struct, &out.Struct + *out = make([]Ttest, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.StructPtr != nil { + in, out := &in.StructPtr, &out.StructPtr + *out = make([]*Ttest, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Ttest) + (*in).DeepCopyInto(*out) + } + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest. +func (in *Ttest) DeepCopy() *Ttest { + if in == nil { + return nil + } + out := new(Ttest) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/structs/doc.go b/code-generator/cmd/deepcopy-gen/output_tests/structs/doc.go new file mode 100644 index 000000000..7e40800b2 --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/structs/doc.go @@ -0,0 +1,40 @@ +/* +Copyright 2016 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package + +// This is a test package. +package structs + +type Inner struct { + Byte byte + // Int8 int8 //TODO: int8 becomes byte in SnippetWriter + Int16 int16 + Int32 int32 + Int64 int64 + Uint8 uint8 + Uint16 uint16 + Uint32 uint32 + Uint64 uint64 + Float32 float32 + Float64 float64 + String string +} + +type Ttest struct { + Inner1 Inner + Inner2 Inner +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/structs/zz_generated.deepcopy.go b/code-generator/cmd/deepcopy-gen/output_tests/structs/zz_generated.deepcopy.go new file mode 100644 index 000000000..992f9b9c2 --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/structs/zz_generated.deepcopy.go @@ -0,0 +1,56 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package structs + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Inner) DeepCopyInto(out *Inner) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Inner. +func (in *Inner) DeepCopy() *Inner { + if in == nil { + return nil + } + out := new(Inner) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Ttest) DeepCopyInto(out *Ttest) { + *out = *in + out.Inner1 = in.Inner1 + out.Inner2 = in.Inner2 + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest. +func (in *Ttest) DeepCopy() *Ttest { + if in == nil { + return nil + } + out := new(Ttest) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/value_fuzzer.go b/code-generator/cmd/deepcopy-gen/output_tests/value_fuzzer.go new file mode 100644 index 000000000..6104aa3cb --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/value_fuzzer.go @@ -0,0 +1,86 @@ +/* +Copyright 2018 The Kubernetes 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 outputtests + +import ( + "reflect" +) + +// ValueFuzz recursively changes all basic type values in an object. Any kind of references will not +// be touched, i.e. the addresses of slices, maps, pointers will stay unchanged. +func ValueFuzz(obj interface{}) { + valueFuzz(reflect.ValueOf(obj)) +} + +func valueFuzz(obj reflect.Value) { + switch obj.Kind() { + case reflect.Array: + for i := 0; i < obj.Len(); i++ { + valueFuzz(obj.Index(i)) + } + case reflect.Slice: + if obj.IsNil() { + // TODO: set non-nil value + } else { + for i := 0; i < obj.Len(); i++ { + valueFuzz(obj.Index(i)) + } + } + case reflect.Interface, reflect.Ptr: + if obj.IsNil() { + // TODO: set non-nil value + } else { + valueFuzz(obj.Elem()) + } + case reflect.Struct: + for i, n := 0, obj.NumField(); i < n; i++ { + valueFuzz(obj.Field(i)) + } + case reflect.Map: + if obj.IsNil() { + // TODO: set non-nil value + } else { + for _, k := range obj.MapKeys() { + // map values are not addressable. We need a copy. + v := obj.MapIndex(k) + copy := reflect.New(v.Type()) + copy.Elem().Set(v) + valueFuzz(copy.Elem()) + obj.SetMapIndex(k, copy.Elem()) + } + // TODO: set some new value + } + case reflect.Func: // ignore, we don't have function types in our API + default: + if !obj.CanSet() { + return + } + switch obj.Kind() { + case reflect.String: + obj.SetString(obj.String() + "x") + case reflect.Bool: + obj.SetBool(!obj.Bool()) + case reflect.Float32, reflect.Float64: + obj.SetFloat(obj.Float()*2.0 + 1.0) + case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: + obj.SetInt(obj.Int() + 1) + case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: + obj.SetUint(obj.Uint() + 1) + default: + } + } +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/a.go b/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/a.go new file mode 100644 index 000000000..fbebe8642 --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/a.go @@ -0,0 +1,171 @@ +/* +Copyright 2016 The Kubernetes 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 wholepkg + +import "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg" + +// Trivial +type StructEmpty struct{} + +// Only primitives +type StructPrimitives struct { + BoolField bool + IntField int + StringField string + FloatField float64 +} +type StructPrimitivesAlias StructPrimitives +type StructEmbedStructPrimitives struct { + StructPrimitives +} +type StructEmbedInt struct { + int //nolint:unused +} +type StructStructPrimitives struct { + StructField StructPrimitives +} + +// Manual DeepCopy method +type ManualStruct struct { + StringField string +} + +func (m ManualStruct) DeepCopy() ManualStruct { + return m +} + +type ManualStructAlias ManualStruct + +type StructEmbedManualStruct struct { + ManualStruct +} + +// Only pointers to primitives +type StructPrimitivePointers struct { + BoolPtrField *bool + IntPtrField *int + StringPtrField *string + FloatPtrField *float64 +} +type StructPrimitivePointersAlias StructPrimitivePointers +type StructEmbedStructPrimitivePointers struct { + StructPrimitivePointers +} +type StructEmbedPointer struct { + *int +} +type StructStructPrimitivePointers struct { + StructField StructPrimitivePointers +} + +// Manual DeepCopy method +type ManualSlice []string + +func (m ManualSlice) DeepCopy() ManualSlice { + r := make(ManualSlice, len(m)) + copy(r, m) + return r +} + +// Slices +type StructSlices struct { + SliceBoolField []bool + SliceByteField []byte + SliceIntField []int + SliceStringField []string + SliceFloatField []float64 + SliceStructPrimitivesField []StructPrimitives + SliceStructPrimitivesAliasField []StructPrimitivesAlias + SliceStructPrimitivePointersField []StructPrimitivePointers + SliceStructPrimitivePointersAliasField []StructPrimitivePointersAlias + SliceSliceIntField [][]int + SliceManualStructField []ManualStruct + ManualSliceField ManualSlice +} +type StructSlicesAlias StructSlices +type StructEmbedStructSlices struct { + StructSlices +} +type StructStructSlices struct { + StructField StructSlices +} + +// Everything +type StructEverything struct { + BoolField bool + IntField int + StringField string + FloatField float64 + StructField StructPrimitives + EmptyStructField StructEmpty + ManualStructField ManualStruct + ManualStructAliasField ManualStructAlias + BoolPtrField *bool + IntPtrField *int + StringPtrField *string + FloatPtrField *float64 + PrimitivePointersField StructPrimitivePointers + ManualStructPtrField *ManualStruct + ManualStructAliasPtrField *ManualStructAlias + SliceBoolField []bool + SliceByteField []byte + SliceIntField []int + SliceStringField []string + SliceFloatField []float64 + SlicesField StructSlices + SliceManualStructField []ManualStruct + ManualSliceField ManualSlice +} + +// An Object +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg.Object +type StructExplicitObject struct { + x int //nolint:unused +} + +// An Object which is used a non-pointer +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg.Object +// +k8s:deepcopy-gen:nonpointer-interfaces=true +type StructNonPointerExplicitObject struct { + x int //nolint:unused +} + +// +k8s:deepcopy-gen=false +type StructTypeMeta struct { +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg.Object +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg.List +type StructObjectAndList struct { +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg.Object +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg.Object +type StructObjectAndObject struct { +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/wholepkg.Selector +// +k8s:deepcopy-gen:interfaces=k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg.Object +type StructExplicitSelectorExplicitObject struct { + StructTypeMeta +} + +type StructInterfaces struct { + ObjectField otherpkg.Object + NilObjectField otherpkg.Object + SelectorField Selector +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/b.go b/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/b.go new file mode 100644 index 000000000..3eb8c01fc --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/b.go @@ -0,0 +1,20 @@ +/* +Copyright 2016 The Kubernetes 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 wholepkg + +// Another type in another file. +type StructB struct{} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/deepcopy_test.go b/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/deepcopy_test.go new file mode 100644 index 000000000..b5089d6d4 --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/deepcopy_test.go @@ -0,0 +1,145 @@ +/* +Copyright 2016 The Kubernetes 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 wholepkg + +import ( + "reflect" + "testing" + + fuzz "github.com/google/gofuzz" +) + +func TestDeepCopyPrimitives(t *testing.T) { + x := StructPrimitives{} + y := StructPrimitives{} + + if !reflect.DeepEqual(&x, &y) { + t.Errorf("objects should be equal to start, but are not") + } + + fuzzer := fuzz.New() + fuzzer.Fuzz(&x) + fuzzer.Fuzz(&y) + + if reflect.DeepEqual(&x, &y) { + t.Errorf("objects should not be equal, but are") + } + + x.DeepCopyInto(&y) + if !reflect.DeepEqual(&x, &y) { + t.Errorf("objects should be equal, but are not") + } +} + +func TestDeepCopyInterfaceFields(t *testing.T) { + x := StructInterfaces{} + y := StructInterfaces{} + + if !reflect.DeepEqual(&x, &y) { + t.Errorf("objects should be equal to start, but are not") + } + + fuzzer := fuzz.New() + + obj := StructExplicitObject{} + fuzzer.Fuzz(&obj) + x.ObjectField = &obj + + sel := StructExplicitSelectorExplicitObject{} + fuzzer.Fuzz(&sel) + x.SelectorField = &sel + + if reflect.DeepEqual(&x, &y) { + t.Errorf("objects should not be equal, but are") + } + + x.DeepCopyInto(&y) + if !reflect.DeepEqual(&x, &y) { + t.Errorf("objects should be equal, but are not") + } +} + +func TestNilCopy(t *testing.T) { + var x *StructB + y := x.DeepCopy() + if y != nil { + t.Errorf("Expected nil as deepcopy of nil, got %+v", y) + } +} + +func assertMethod(t *testing.T, typ reflect.Type, name string) { + if _, found := typ.MethodByName(name); !found { + t.Errorf("StructExplicitObject must have %v method", name) + } +} + +func assertNotMethod(t *testing.T, typ reflect.Type, name string) { + if _, found := typ.MethodByName(name); found { + t.Errorf("%v must not have %v method", typ, name) + } +} + +func TestInterfaceTypes(t *testing.T) { + explicitObject := reflect.TypeOf(&StructExplicitObject{}) + assertMethod(t, explicitObject, "DeepCopyObject") + + typeMeta := reflect.TypeOf(&StructTypeMeta{}) + assertNotMethod(t, typeMeta, "DeepCopy") + + objectAndList := reflect.TypeOf(&StructObjectAndList{}) + assertMethod(t, objectAndList, "DeepCopyObject") + assertMethod(t, objectAndList, "DeepCopyList") + + objectAndObject := reflect.TypeOf(&StructObjectAndObject{}) + assertMethod(t, objectAndObject, "DeepCopyObject") + + explicitSelectorExplicitObject := reflect.TypeOf(&StructExplicitSelectorExplicitObject{}) + assertMethod(t, explicitSelectorExplicitObject, "DeepCopySelector") + assertMethod(t, explicitSelectorExplicitObject, "DeepCopyObject") +} + +func TestInterfaceDeepCopy(t *testing.T) { + x := StructExplicitObject{} + + fuzzer := fuzz.New() + fuzzer.Fuzz(&x) + + yObj := x.DeepCopyObject() + y, ok := yObj.(*StructExplicitObject) + if !ok { + t.Fatalf("epxected StructExplicitObject from StructExplicitObject.DeepCopyObject, got: %t", yObj) + } + if !reflect.DeepEqual(y, &x) { + t.Error("objects should be equal, but are not") + } +} + +func TestInterfaceNonPointerDeepCopy(t *testing.T) { + x := StructNonPointerExplicitObject{} + + fuzzer := fuzz.New() + fuzzer.Fuzz(&x) + + yObj := x.DeepCopyObject() + y, ok := yObj.(StructNonPointerExplicitObject) + if !ok { + t.Fatalf("epxected StructNonPointerExplicitObject from StructNonPointerExplicitObject.DeepCopyObject, got: %t", yObj) + } + if !reflect.DeepEqual(y, x) { + t.Error("objects should be equal, but are not") + } +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/doc.go b/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/doc.go new file mode 100644 index 000000000..10399986f --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2016 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package + +// This is a test package. +package wholepkg diff --git a/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/interfaces.go b/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/interfaces.go new file mode 100644 index 000000000..e5b3c7de4 --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/interfaces.go @@ -0,0 +1,21 @@ +/* +Copyright 2017 The Kubernetes 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 wholepkg + +type Selector interface { + DeepCopySelector() Selector +} diff --git a/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/zz_generated.deepcopy.go b/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/zz_generated.deepcopy.go new file mode 100644 index 000000000..0c7b4699e --- /dev/null +++ b/code-generator/cmd/deepcopy-gen/output_tests/wholepkg/zz_generated.deepcopy.go @@ -0,0 +1,761 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package wholepkg + +import ( + otherpkg "k8s.io/code-generator/cmd/deepcopy-gen/output_tests/otherpkg" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in ManualSlice) DeepCopyInto(out *ManualSlice) { + { + in := &in + *out = in.DeepCopy() + return + } +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManualStruct) DeepCopyInto(out *ManualStruct) { + *out = in.DeepCopy() + return +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ManualStructAlias) DeepCopyInto(out *ManualStructAlias) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ManualStructAlias. +func (in *ManualStructAlias) DeepCopy() *ManualStructAlias { + if in == nil { + return nil + } + out := new(ManualStructAlias) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructB) DeepCopyInto(out *StructB) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructB. +func (in *StructB) DeepCopy() *StructB { + if in == nil { + return nil + } + out := new(StructB) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructEmbedInt) DeepCopyInto(out *StructEmbedInt) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructEmbedInt. +func (in *StructEmbedInt) DeepCopy() *StructEmbedInt { + if in == nil { + return nil + } + out := new(StructEmbedInt) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructEmbedManualStruct) DeepCopyInto(out *StructEmbedManualStruct) { + *out = *in + out.ManualStruct = in.ManualStruct.DeepCopy() + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructEmbedManualStruct. +func (in *StructEmbedManualStruct) DeepCopy() *StructEmbedManualStruct { + if in == nil { + return nil + } + out := new(StructEmbedManualStruct) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructEmbedPointer) DeepCopyInto(out *StructEmbedPointer) { + *out = *in + if in.int != nil { + in, out := &in.int, &out.int + *out = new(int) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructEmbedPointer. +func (in *StructEmbedPointer) DeepCopy() *StructEmbedPointer { + if in == nil { + return nil + } + out := new(StructEmbedPointer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructEmbedStructPrimitivePointers) DeepCopyInto(out *StructEmbedStructPrimitivePointers) { + *out = *in + in.StructPrimitivePointers.DeepCopyInto(&out.StructPrimitivePointers) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructEmbedStructPrimitivePointers. +func (in *StructEmbedStructPrimitivePointers) DeepCopy() *StructEmbedStructPrimitivePointers { + if in == nil { + return nil + } + out := new(StructEmbedStructPrimitivePointers) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructEmbedStructPrimitives) DeepCopyInto(out *StructEmbedStructPrimitives) { + *out = *in + out.StructPrimitives = in.StructPrimitives + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructEmbedStructPrimitives. +func (in *StructEmbedStructPrimitives) DeepCopy() *StructEmbedStructPrimitives { + if in == nil { + return nil + } + out := new(StructEmbedStructPrimitives) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructEmbedStructSlices) DeepCopyInto(out *StructEmbedStructSlices) { + *out = *in + in.StructSlices.DeepCopyInto(&out.StructSlices) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructEmbedStructSlices. +func (in *StructEmbedStructSlices) DeepCopy() *StructEmbedStructSlices { + if in == nil { + return nil + } + out := new(StructEmbedStructSlices) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructEmpty) DeepCopyInto(out *StructEmpty) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructEmpty. +func (in *StructEmpty) DeepCopy() *StructEmpty { + if in == nil { + return nil + } + out := new(StructEmpty) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructEverything) DeepCopyInto(out *StructEverything) { + *out = *in + out.StructField = in.StructField + out.EmptyStructField = in.EmptyStructField + out.ManualStructField = in.ManualStructField.DeepCopy() + out.ManualStructAliasField = in.ManualStructAliasField + if in.BoolPtrField != nil { + in, out := &in.BoolPtrField, &out.BoolPtrField + *out = new(bool) + **out = **in + } + if in.IntPtrField != nil { + in, out := &in.IntPtrField, &out.IntPtrField + *out = new(int) + **out = **in + } + if in.StringPtrField != nil { + in, out := &in.StringPtrField, &out.StringPtrField + *out = new(string) + **out = **in + } + if in.FloatPtrField != nil { + in, out := &in.FloatPtrField, &out.FloatPtrField + *out = new(float64) + **out = **in + } + in.PrimitivePointersField.DeepCopyInto(&out.PrimitivePointersField) + if in.ManualStructPtrField != nil { + in, out := &in.ManualStructPtrField, &out.ManualStructPtrField + x := (*in).DeepCopy() + *out = &x + } + if in.ManualStructAliasPtrField != nil { + in, out := &in.ManualStructAliasPtrField, &out.ManualStructAliasPtrField + *out = new(ManualStructAlias) + **out = **in + } + if in.SliceBoolField != nil { + in, out := &in.SliceBoolField, &out.SliceBoolField + *out = make([]bool, len(*in)) + copy(*out, *in) + } + if in.SliceByteField != nil { + in, out := &in.SliceByteField, &out.SliceByteField + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.SliceIntField != nil { + in, out := &in.SliceIntField, &out.SliceIntField + *out = make([]int, len(*in)) + copy(*out, *in) + } + if in.SliceStringField != nil { + in, out := &in.SliceStringField, &out.SliceStringField + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.SliceFloatField != nil { + in, out := &in.SliceFloatField, &out.SliceFloatField + *out = make([]float64, len(*in)) + copy(*out, *in) + } + in.SlicesField.DeepCopyInto(&out.SlicesField) + if in.SliceManualStructField != nil { + in, out := &in.SliceManualStructField, &out.SliceManualStructField + *out = make([]ManualStruct, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + out.ManualSliceField = in.ManualSliceField.DeepCopy() + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructEverything. +func (in *StructEverything) DeepCopy() *StructEverything { + if in == nil { + return nil + } + out := new(StructEverything) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructExplicitObject) DeepCopyInto(out *StructExplicitObject) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructExplicitObject. +func (in *StructExplicitObject) DeepCopy() *StructExplicitObject { + if in == nil { + return nil + } + out := new(StructExplicitObject) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.Object. +func (in *StructExplicitObject) DeepCopyObject() otherpkg.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructExplicitSelectorExplicitObject) DeepCopyInto(out *StructExplicitSelectorExplicitObject) { + *out = *in + out.StructTypeMeta = in.StructTypeMeta + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructExplicitSelectorExplicitObject. +func (in *StructExplicitSelectorExplicitObject) DeepCopy() *StructExplicitSelectorExplicitObject { + if in == nil { + return nil + } + out := new(StructExplicitSelectorExplicitObject) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.Object. +func (in *StructExplicitSelectorExplicitObject) DeepCopyObject() otherpkg.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopySelector is an autogenerated deepcopy function, copying the receiver, creating a new Selector. +func (in *StructExplicitSelectorExplicitObject) DeepCopySelector() Selector { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructInterfaces) DeepCopyInto(out *StructInterfaces) { + *out = *in + if in.ObjectField != nil { + out.ObjectField = in.ObjectField.DeepCopyObject() + } + if in.NilObjectField != nil { + out.NilObjectField = in.NilObjectField.DeepCopyObject() + } + if in.SelectorField != nil { + out.SelectorField = in.SelectorField.DeepCopySelector() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructInterfaces. +func (in *StructInterfaces) DeepCopy() *StructInterfaces { + if in == nil { + return nil + } + out := new(StructInterfaces) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructNonPointerExplicitObject) DeepCopyInto(out *StructNonPointerExplicitObject) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructNonPointerExplicitObject. +func (in *StructNonPointerExplicitObject) DeepCopy() *StructNonPointerExplicitObject { + if in == nil { + return nil + } + out := new(StructNonPointerExplicitObject) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.Object. +func (in StructNonPointerExplicitObject) DeepCopyObject() otherpkg.Object { + return *in.DeepCopy() +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructObjectAndList) DeepCopyInto(out *StructObjectAndList) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructObjectAndList. +func (in *StructObjectAndList) DeepCopy() *StructObjectAndList { + if in == nil { + return nil + } + out := new(StructObjectAndList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyList is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.List. +func (in *StructObjectAndList) DeepCopyList() otherpkg.List { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.Object. +func (in *StructObjectAndList) DeepCopyObject() otherpkg.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructObjectAndObject) DeepCopyInto(out *StructObjectAndObject) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructObjectAndObject. +func (in *StructObjectAndObject) DeepCopy() *StructObjectAndObject { + if in == nil { + return nil + } + out := new(StructObjectAndObject) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new otherpkg.Object. +func (in *StructObjectAndObject) DeepCopyObject() otherpkg.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructPrimitivePointers) DeepCopyInto(out *StructPrimitivePointers) { + *out = *in + if in.BoolPtrField != nil { + in, out := &in.BoolPtrField, &out.BoolPtrField + *out = new(bool) + **out = **in + } + if in.IntPtrField != nil { + in, out := &in.IntPtrField, &out.IntPtrField + *out = new(int) + **out = **in + } + if in.StringPtrField != nil { + in, out := &in.StringPtrField, &out.StringPtrField + *out = new(string) + **out = **in + } + if in.FloatPtrField != nil { + in, out := &in.FloatPtrField, &out.FloatPtrField + *out = new(float64) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructPrimitivePointers. +func (in *StructPrimitivePointers) DeepCopy() *StructPrimitivePointers { + if in == nil { + return nil + } + out := new(StructPrimitivePointers) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructPrimitivePointersAlias) DeepCopyInto(out *StructPrimitivePointersAlias) { + *out = *in + if in.BoolPtrField != nil { + in, out := &in.BoolPtrField, &out.BoolPtrField + *out = new(bool) + **out = **in + } + if in.IntPtrField != nil { + in, out := &in.IntPtrField, &out.IntPtrField + *out = new(int) + **out = **in + } + if in.StringPtrField != nil { + in, out := &in.StringPtrField, &out.StringPtrField + *out = new(string) + **out = **in + } + if in.FloatPtrField != nil { + in, out := &in.FloatPtrField, &out.FloatPtrField + *out = new(float64) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructPrimitivePointersAlias. +func (in *StructPrimitivePointersAlias) DeepCopy() *StructPrimitivePointersAlias { + if in == nil { + return nil + } + out := new(StructPrimitivePointersAlias) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructPrimitives) DeepCopyInto(out *StructPrimitives) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructPrimitives. +func (in *StructPrimitives) DeepCopy() *StructPrimitives { + if in == nil { + return nil + } + out := new(StructPrimitives) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructPrimitivesAlias) DeepCopyInto(out *StructPrimitivesAlias) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructPrimitivesAlias. +func (in *StructPrimitivesAlias) DeepCopy() *StructPrimitivesAlias { + if in == nil { + return nil + } + out := new(StructPrimitivesAlias) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructSlices) DeepCopyInto(out *StructSlices) { + *out = *in + if in.SliceBoolField != nil { + in, out := &in.SliceBoolField, &out.SliceBoolField + *out = make([]bool, len(*in)) + copy(*out, *in) + } + if in.SliceByteField != nil { + in, out := &in.SliceByteField, &out.SliceByteField + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.SliceIntField != nil { + in, out := &in.SliceIntField, &out.SliceIntField + *out = make([]int, len(*in)) + copy(*out, *in) + } + if in.SliceStringField != nil { + in, out := &in.SliceStringField, &out.SliceStringField + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.SliceFloatField != nil { + in, out := &in.SliceFloatField, &out.SliceFloatField + *out = make([]float64, len(*in)) + copy(*out, *in) + } + if in.SliceStructPrimitivesField != nil { + in, out := &in.SliceStructPrimitivesField, &out.SliceStructPrimitivesField + *out = make([]StructPrimitives, len(*in)) + copy(*out, *in) + } + if in.SliceStructPrimitivesAliasField != nil { + in, out := &in.SliceStructPrimitivesAliasField, &out.SliceStructPrimitivesAliasField + *out = make([]StructPrimitivesAlias, len(*in)) + copy(*out, *in) + } + if in.SliceStructPrimitivePointersField != nil { + in, out := &in.SliceStructPrimitivePointersField, &out.SliceStructPrimitivePointersField + *out = make([]StructPrimitivePointers, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.SliceStructPrimitivePointersAliasField != nil { + in, out := &in.SliceStructPrimitivePointersAliasField, &out.SliceStructPrimitivePointersAliasField + *out = make([]StructPrimitivePointersAlias, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.SliceSliceIntField != nil { + in, out := &in.SliceSliceIntField, &out.SliceSliceIntField + *out = make([][]int, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make([]int, len(*in)) + copy(*out, *in) + } + } + } + if in.SliceManualStructField != nil { + in, out := &in.SliceManualStructField, &out.SliceManualStructField + *out = make([]ManualStruct, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + out.ManualSliceField = in.ManualSliceField.DeepCopy() + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructSlices. +func (in *StructSlices) DeepCopy() *StructSlices { + if in == nil { + return nil + } + out := new(StructSlices) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructSlicesAlias) DeepCopyInto(out *StructSlicesAlias) { + *out = *in + if in.SliceBoolField != nil { + in, out := &in.SliceBoolField, &out.SliceBoolField + *out = make([]bool, len(*in)) + copy(*out, *in) + } + if in.SliceByteField != nil { + in, out := &in.SliceByteField, &out.SliceByteField + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.SliceIntField != nil { + in, out := &in.SliceIntField, &out.SliceIntField + *out = make([]int, len(*in)) + copy(*out, *in) + } + if in.SliceStringField != nil { + in, out := &in.SliceStringField, &out.SliceStringField + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.SliceFloatField != nil { + in, out := &in.SliceFloatField, &out.SliceFloatField + *out = make([]float64, len(*in)) + copy(*out, *in) + } + if in.SliceStructPrimitivesField != nil { + in, out := &in.SliceStructPrimitivesField, &out.SliceStructPrimitivesField + *out = make([]StructPrimitives, len(*in)) + copy(*out, *in) + } + if in.SliceStructPrimitivesAliasField != nil { + in, out := &in.SliceStructPrimitivesAliasField, &out.SliceStructPrimitivesAliasField + *out = make([]StructPrimitivesAlias, len(*in)) + copy(*out, *in) + } + if in.SliceStructPrimitivePointersField != nil { + in, out := &in.SliceStructPrimitivePointersField, &out.SliceStructPrimitivePointersField + *out = make([]StructPrimitivePointers, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.SliceStructPrimitivePointersAliasField != nil { + in, out := &in.SliceStructPrimitivePointersAliasField, &out.SliceStructPrimitivePointersAliasField + *out = make([]StructPrimitivePointersAlias, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.SliceSliceIntField != nil { + in, out := &in.SliceSliceIntField, &out.SliceSliceIntField + *out = make([][]int, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make([]int, len(*in)) + copy(*out, *in) + } + } + } + if in.SliceManualStructField != nil { + in, out := &in.SliceManualStructField, &out.SliceManualStructField + *out = make([]ManualStruct, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + out.ManualSliceField = in.ManualSliceField.DeepCopy() + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructSlicesAlias. +func (in *StructSlicesAlias) DeepCopy() *StructSlicesAlias { + if in == nil { + return nil + } + out := new(StructSlicesAlias) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructStructPrimitivePointers) DeepCopyInto(out *StructStructPrimitivePointers) { + *out = *in + in.StructField.DeepCopyInto(&out.StructField) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructStructPrimitivePointers. +func (in *StructStructPrimitivePointers) DeepCopy() *StructStructPrimitivePointers { + if in == nil { + return nil + } + out := new(StructStructPrimitivePointers) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructStructPrimitives) DeepCopyInto(out *StructStructPrimitives) { + *out = *in + out.StructField = in.StructField + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructStructPrimitives. +func (in *StructStructPrimitives) DeepCopy() *StructStructPrimitives { + if in == nil { + return nil + } + out := new(StructStructPrimitives) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructStructSlices) DeepCopyInto(out *StructStructSlices) { + *out = *in + in.StructField.DeepCopyInto(&out.StructField) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructStructSlices. +func (in *StructStructSlices) DeepCopy() *StructStructSlices { + if in == nil { + return nil + } + out := new(StructStructSlices) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/cmd/defaulter-gen/args/args.go b/code-generator/cmd/defaulter-gen/args/args.go new file mode 100644 index 000000000..52a9d1c67 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/args/args.go @@ -0,0 +1,53 @@ +/* +Copyright 2017 The Kubernetes 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" +) + +type Args struct { + OutputFile string + ExtraPeerDirs []string // Always consider these as last-ditch possibilities for conversions. + GoHeaderFile string +} + +// New returns default arguments for the generator. +func New() *Args { + return &Args{} +} + +// AddFlags add the generator flags to the flag set. +func (args *Args) AddFlags(fs *pflag.FlagSet) { + fs.StringVar(&args.OutputFile, "output-file", "generated.defaults.go", + "the name of the file to be generated") + fs.StringSliceVar(&args.ExtraPeerDirs, "extra-peer-dirs", args.ExtraPeerDirs, + "Comma-separated list of import paths which are considered, after tag-specified peers, for conversions.") + fs.StringVar(&args.GoHeaderFile, "go-header-file", "", + "the path to a file containing boilerplate header text; the string \"YEAR\" will be replaced with the current 4-digit year") +} + +// Validate checks the given arguments. +func (args *Args) Validate() error { + if len(args.OutputFile) == 0 { + return fmt.Errorf("--output-file must be specified") + } + + return nil +} diff --git a/code-generator/cmd/defaulter-gen/generators/defaulter.go b/code-generator/cmd/defaulter-gen/generators/defaulter.go new file mode 100644 index 000000000..f7a6864c7 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/generators/defaulter.go @@ -0,0 +1,1235 @@ +/* +Copyright 2016 The Kubernetes 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 ( + "bytes" + "encoding/json" + "fmt" + "io" + "path" + "reflect" + "regexp" + "strconv" + "strings" + + "k8s.io/code-generator/cmd/defaulter-gen/args" + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + "k8s.io/klog/v2" +) + +var typeZeroValue = map[string]interface{}{ + "uint": 0., + "uint8": 0., + "uint16": 0., + "uint32": 0., + "uint64": 0., + "int": 0., + "int8": 0., + "int16": 0., + "int32": 0., + "int64": 0., + "byte": 0., + "float64": 0., + "float32": 0., + "bool": false, + "time.Time": "", + "string": "", + "integer": 0., + "number": 0., + "boolean": false, + "[]byte": "", // base64 encoded characters + "interface{}": interface{}(nil), +} + +// These are the comment tags that carry parameters for defaulter generation. +const tagName = "k8s:defaulter-gen" +const inputTagName = "k8s:defaulter-gen-input" +const defaultTagName = "default" + +func extractDefaultTag(comments []string) []string { + return gengo.ExtractCommentTags("+", comments)[defaultTagName] +} + +func extractTag(comments []string) []string { + return gengo.ExtractCommentTags("+", comments)[tagName] +} + +func extractInputTag(comments []string) []string { + return gengo.ExtractCommentTags("+", comments)[inputTagName] +} + +func checkTag(comments []string, require ...string) bool { + values := gengo.ExtractCommentTags("+", comments)[tagName] + if len(require) == 0 { + return len(values) == 1 && values[0] == "" + } + return reflect.DeepEqual(values, require) +} + +func defaultFnNamer() *namer.NameStrategy { + return &namer.NameStrategy{ + Prefix: "SetDefaults_", + Join: func(pre string, in []string, post string) string { + return pre + strings.Join(in, "_") + post + }, + } +} + +func objectDefaultFnNamer() *namer.NameStrategy { + return &namer.NameStrategy{ + Prefix: "SetObjectDefaults_", + Join: func(pre string, in []string, post string) string { + return pre + strings.Join(in, "_") + post + }, + } +} + +// NameSystems returns the name system used by the generators in this package. +func NameSystems() namer.NameSystems { + return namer.NameSystems{ + "public": namer.NewPublicNamer(1), + "raw": namer.NewRawNamer("", nil), + "defaultfn": defaultFnNamer(), + "objectdefaultfn": objectDefaultFnNamer(), + } +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +// defaults holds the declared defaulting functions for a given type (all defaulting functions +// are expected to be func(1)) +type defaults struct { + // object is the defaulter function for a top level type (typically one with TypeMeta) that + // invokes all child defaulters. May be nil if the object defaulter has not yet been generated. + object *types.Type + // base is a defaulter function defined for a type SetDefaults_Pod which does not invoke all + // child defaults - the base defaulter alone is insufficient to default a type + base *types.Type + // additional is zero or more defaulter functions of the form SetDefaults_Pod_XXXX that can be + // included in the Object defaulter. + additional []*types.Type +} + +// All of the types in conversions map are of type "DeclarationOf" with +// the underlying type being "Func". +type defaulterFuncMap map[*types.Type]defaults + +// Returns all manually-defined defaulting functions in the package. +func getManualDefaultingFunctions(context *generator.Context, pkg *types.Package, manualMap defaulterFuncMap) { + buffer := &bytes.Buffer{} + sw := generator.NewSnippetWriter(buffer, context, "$", "$") + + for _, f := range pkg.Functions { + if f.Underlying == nil || f.Underlying.Kind != types.Func { + klog.Errorf("Malformed function: %#v", f) + continue + } + if f.Underlying.Signature == nil { + klog.Errorf("Function without signature: %#v", f) + continue + } + signature := f.Underlying.Signature + // Check whether the function is defaulting function. + // Note that all of them have signature: + // object: func SetObjectDefaults_inType(*inType) + // base: func SetDefaults_inType(*inType) + // additional: func SetDefaults_inType_Qualifier(*inType) + if signature.Receiver != nil { + continue + } + if len(signature.Parameters) != 1 { + continue + } + if len(signature.Results) != 0 { + continue + } + inType := signature.Parameters[0].Type + if inType.Kind != types.Pointer { + continue + } + // Check if this is the primary defaulter. + args := defaultingArgsFromType(inType.Elem) + sw.Do("$.inType|defaultfn$", args) + switch { + case f.Name.Name == buffer.String(): + key := inType.Elem + // We might scan the same package twice, and that's OK. + v, ok := manualMap[key] + if ok && v.base != nil && v.base.Name.Package != pkg.Path { + panic(fmt.Sprintf("duplicate static defaulter defined: %#v", key)) + } + v.base = f + manualMap[key] = v + klog.V(6).Infof("found base defaulter function for %s from %s", key.Name, f.Name) + // Is one of the additional defaulters - a top level defaulter on a type that is + // also invoked. + case strings.HasPrefix(f.Name.Name, buffer.String()+"_"): + key := inType.Elem + v, ok := manualMap[key] + if ok { + exists := false + for _, existing := range v.additional { + if existing.Name == f.Name { + exists = true + break + } + } + if exists { + continue + } + } + v.additional = append(v.additional, f) + manualMap[key] = v + klog.V(6).Infof("found additional defaulter function for %s from %s", key.Name, f.Name) + } + buffer.Reset() + sw.Do("$.inType|objectdefaultfn$", args) + if f.Name.Name == buffer.String() { + key := inType.Elem + // We might scan the same package twice, and that's OK. + v, ok := manualMap[key] + if ok && v.base != nil && v.base.Name.Package != pkg.Path { + panic(fmt.Sprintf("duplicate static defaulter defined: %#v", key)) + } + v.object = f + manualMap[key] = v + klog.V(6).Infof("found object defaulter function for %s from %s", key.Name, f.Name) + } + buffer.Reset() + } +} + +func GetTargets(context *generator.Context, args *args.Args) []generator.Target { + boilerplate, err := gengo.GoBoilerplate(args.GoHeaderFile, gengo.StdBuildTag, gengo.StdGeneratedBy) + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + targets := []generator.Target{} + + // Accumulate pre-existing default functions. + // TODO: This is too ad-hoc. We need a better way. + existingDefaulters := defaulterFuncMap{} + + buffer := &bytes.Buffer{} + sw := generator.NewSnippetWriter(buffer, context, "$", "$") + + // First load other "input" packages. We do this as a single call because + // it is MUCH faster. + inputPkgs := make([]string, 0, len(context.Inputs)) + pkgToInput := map[string]string{} + for _, i := range context.Inputs { + klog.V(5).Infof("considering pkg %q", i) + + pkg := context.Universe[i] + + // if the types are not in the same package where the defaulter functions to be generated + inputTags := extractInputTag(pkg.Comments) + if len(inputTags) > 1 { + panic(fmt.Sprintf("there may only be one input tag, got %#v", inputTags)) + } + if len(inputTags) == 1 { + inputPath := inputTags[0] + if strings.HasPrefix(inputPath, "./") || strings.HasPrefix(inputPath, "../") { + // this is a relative dir, which will not work under gomodules. + // join with the local package path, but warn + klog.Warningf("relative path %s=%s will not work under gomodule mode; use full package path (as used by 'import') instead", inputTagName, inputPath) + inputPath = path.Join(pkg.Path, inputTags[0]) + } + + klog.V(5).Infof(" input pkg %v", inputPath) + inputPkgs = append(inputPkgs, inputPath) + pkgToInput[i] = inputPath + } else { + pkgToInput[i] = i + } + } + + // Make sure explicit peer-packages are added. + var peerPkgs []string + for _, pkg := range args.ExtraPeerDirs { + // In case someone specifies a peer as a path into vendor, convert + // it to its "real" package path. + if i := strings.Index(pkg, "/vendor/"); i != -1 { + pkg = pkg[i+len("/vendor/"):] + } + peerPkgs = append(peerPkgs, pkg) + } + if expanded, err := context.FindPackages(peerPkgs...); err != nil { + klog.Fatalf("cannot find peer packages: %v", err) + } else { + peerPkgs = expanded // now in fully canonical form + } + inputPkgs = append(inputPkgs, peerPkgs...) + + if len(inputPkgs) > 0 { + if _, err := context.LoadPackages(inputPkgs...); err != nil { + klog.Fatalf("cannot load packages: %v", err) + } + } + // update context.Order to the latest context.Universe + orderer := namer.Orderer{Namer: namer.NewPublicNamer(1)} + context.Order = orderer.OrderUniverse(context.Universe) + + for _, i := range context.Inputs { + pkg := context.Universe[i] + + // typesPkg is where the types that needs defaulter are defined. + // Sometimes it is different from pkg. For example, kubernetes core/v1 + // types are defined in k8s.io/api/core/v1, while the pkg which holds + // defaulter code is at k/k/pkg/api/v1. + typesPkg := pkg + + // Add defaulting functions. + getManualDefaultingFunctions(context, pkg, existingDefaulters) + + // Also look for defaulting functions in peer-packages. + for _, pp := range peerPkgs { + getManualDefaultingFunctions(context, context.Universe[pp], existingDefaulters) + } + + typesWith := extractTag(pkg.Comments) + shouldCreateObjectDefaulterFn := func(t *types.Type) bool { + if defaults, ok := existingDefaulters[t]; ok && defaults.object != nil { + // A default generator is defined + baseTypeName := "" + if defaults.base != nil { + baseTypeName = defaults.base.Name.String() + } + klog.V(5).Infof(" an object defaulter already exists as %s", baseTypeName) + return false + } + // opt-out + if checkTag(t.SecondClosestCommentLines, "false") { + return false + } + // opt-in + if checkTag(t.SecondClosestCommentLines, "true") { + return true + } + // For every k8s:defaulter-gen tag at the package level, interpret the value as a + // field name (like TypeMeta, ListMeta, ObjectMeta) and trigger defaulter generation + // for any type with any of the matching field names. Provides a more useful package + // level defaulting than global (because we only need defaulters on a subset of objects - + // usually those with TypeMeta). + if t.Kind == types.Struct && len(typesWith) > 0 { + for _, field := range t.Members { + for _, s := range typesWith { + if field.Name == s { + return true + } + } + } + } + return false + } + + // Find the right input pkg, which might not be this one. + inputPath := pkgToInput[i] + typesPkg = context.Universe[inputPath] + + newDefaulters := defaulterFuncMap{} + for _, t := range typesPkg.Types { + if !shouldCreateObjectDefaulterFn(t) { + continue + } + if namer.IsPrivateGoName(t.Name.Name) { + // We won't be able to convert to a private type. + klog.V(5).Infof(" found a type %v, but it is a private name", t) + continue + } + + // create a synthetic type we can use during generation + newDefaulters[t] = defaults{} + } + + // only generate defaulters for objects that actually have defined defaulters + // prevents empty defaulters from being registered + for { + promoted := 0 + for t, d := range newDefaulters { + if d.object != nil { + continue + } + if newCallTreeForType(existingDefaulters, newDefaulters).build(t, true) != nil { + args := defaultingArgsFromType(t) + sw.Do("$.inType|objectdefaultfn$", args) + newDefaulters[t] = defaults{ + object: &types.Type{ + Name: types.Name{ + Package: pkg.Path, + Name: buffer.String(), + }, + Kind: types.Func, + }, + } + buffer.Reset() + promoted++ + } + } + if promoted != 0 { + continue + } + + // prune any types that were not used + for t, d := range newDefaulters { + if d.object == nil { + klog.V(6).Infof("did not generate defaulter for %s because no child defaulters were registered", t.Name) + delete(newDefaulters, t) + } + } + break + } + + if len(newDefaulters) == 0 { + klog.V(5).Infof("no defaulters in package %s", pkg.Name) + } + + targets = append(targets, + &generator.SimpleTarget{ + PkgName: path.Base(pkg.Path), + PkgPath: pkg.Path, + PkgDir: pkg.Dir, // output pkg is the same as the input + HeaderComment: boilerplate, + + FilterFunc: func(c *generator.Context, t *types.Type) bool { + return t.Name.Package == typesPkg.Path + }, + + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + return []generator.Generator{ + NewGenDefaulter(args.OutputFile, typesPkg.Path, pkg.Path, existingDefaulters, newDefaulters, peerPkgs), + } + }, + }) + } + return targets +} + +// callTreeForType contains fields necessary to build a tree for types. +type callTreeForType struct { + existingDefaulters defaulterFuncMap + newDefaulters defaulterFuncMap + currentlyBuildingTypes map[*types.Type]bool +} + +func newCallTreeForType(existingDefaulters, newDefaulters defaulterFuncMap) *callTreeForType { + return &callTreeForType{ + existingDefaulters: existingDefaulters, + newDefaulters: newDefaulters, + currentlyBuildingTypes: make(map[*types.Type]bool), + } +} + +// resolveType follows pointers and aliases of `t` until reaching the first +// non-pointer type in `t's` herarchy +func resolveTypeAndDepth(t *types.Type) (*types.Type, int) { + var prev *types.Type + depth := 0 + for prev != t { + prev = t + if t.Kind == types.Alias { + t = t.Underlying + } else if t.Kind == types.Pointer { + t = t.Elem + depth += 1 + } + } + return t, depth +} + +// getPointerElementPath follows pointers and aliases to returns all +// pointer elements in the path from the given type, to its base value type. +// +// Example: +// +// type MyString string +// type MyStringPointer *MyString +// type MyStringPointerPointer *MyStringPointer +// type MyStringAlias MyStringPointer +// type MyStringAliasPointer *MyStringAlias +// type MyStringAliasDoublePointer **MyStringAlias +// +// t | defaultPointerElementPath(t) +// ---------------------------|---------------------------------------- +// MyString | [] +// MyStringPointer | [MyString] +// MyStringPointerPointer | [MyStringPointer, MyString] +// MyStringAlias | [MyStringPointer, MyString] +// MyStringAliasPointer | [MyStringAlias, MyStringPointer, MyString] +// MyStringAliasDoublePointer | [*MyStringAlias, MyStringAlias, MyStringPointer, MyString] +func getPointerElementPath(t *types.Type) []*types.Type { + var path []*types.Type + for t != nil { + switch t.Kind { + case types.Alias: + t = t.Underlying + case types.Pointer: + t = t.Elem + path = append(path, t) + default: + t = nil + } + } + return path +} + +// getNestedDefault returns the first default value when resolving alias types +func getNestedDefault(t *types.Type) string { + var prev *types.Type + for prev != t { + prev = t + defaultMap := extractDefaultTag(t.CommentLines) + if len(defaultMap) == 1 && defaultMap[0] != "" { + return defaultMap[0] + } + if t.Kind == types.Alias { + t = t.Underlying + } else if t.Kind == types.Pointer { + t = t.Elem + } + } + return "" +} + +var refRE = regexp.MustCompile(`^ref\((?P[^"]+)\)$`) +var refREIdentIndex = refRE.SubexpIndex("reference") + +// parseSymbolReference looks for strings that match one of the following: +// - ref(Ident) +// - ref(pkgpath.Ident) +// If the input string matches either of these, it will return the (optional) +// pkgpath, the Ident, and true. Otherwise it will return empty strings and +// false. +func parseSymbolReference(s, sourcePackage string) (types.Name, bool) { + matches := refRE.FindStringSubmatch(s) + if len(matches) < refREIdentIndex || matches[refREIdentIndex] == "" { + return types.Name{}, false + } + + contents := matches[refREIdentIndex] + name := types.ParseFullyQualifiedName(contents) + if len(name.Package) == 0 { + name.Package = sourcePackage + } + return name, true +} + +func populateDefaultValue(node *callNode, t *types.Type, tags string, commentLines []string, commentPackage string) *callNode { + defaultMap := extractDefaultTag(commentLines) + var defaultString string + if len(defaultMap) == 1 { + defaultString = defaultMap[0] + } else if len(defaultMap) > 1 { + klog.Fatalf("Found more than one default tag for %v", t.Kind) + } + + baseT, depth := resolveTypeAndDepth(t) + if depth > 0 && defaultString == "" { + defaultString = getNestedDefault(t) + } + + if len(defaultString) == 0 { + return node + } + var symbolReference types.Name + var defaultValue interface{} + if id, ok := parseSymbolReference(defaultString, commentPackage); ok { + symbolReference = id + defaultString = "" + } else if err := json.Unmarshal([]byte(defaultString), &defaultValue); err != nil { + klog.Fatalf("Failed to unmarshal default: %v", err) + } + + if defaultValue != nil { + zero := typeZeroValue[t.String()] + if reflect.DeepEqual(defaultValue, zero) { + // If the default value annotation matches the default value for the type, + // do not generate any defaulting function + return node + } + } + + // callNodes are not automatically generated for primitive types. Generate one if the callNode does not exist + if node == nil { + node = &callNode{} + node.markerOnly = true + } + + node.defaultIsPrimitive = baseT.IsPrimitive() + node.defaultType = baseT + node.defaultTopLevelType = t + node.defaultValue.InlineConstant = defaultString + node.defaultValue.SymbolReference = symbolReference + return node +} + +// build creates a tree of paths to fields (based on how they would be accessed in Go - pointer, elem, +// slice, or key) and the functions that should be invoked on each field. An in-order traversal of the resulting tree +// can be used to generate a Go function that invokes each nested function on the appropriate type. The return +// value may be nil if there are no functions to call on type or the type is a primitive (Defaulters can only be +// invoked on structs today). When root is true this function will not use a newDefaulter. existingDefaulters should +// contain all defaulting functions by type defined in code - newDefaulters should contain all object defaulters +// that could be or will be generated. If newDefaulters has an entry for a type, but the 'object' field is nil, +// this function skips adding that defaulter - this allows us to avoid generating object defaulter functions for +// list types that call empty defaulters. +func (c *callTreeForType) build(t *types.Type, root bool) *callNode { + parent := &callNode{} + + if root { + // the root node is always a pointer + parent.elem = true + } + + defaults := c.existingDefaulters[t] + newDefaults, generated := c.newDefaulters[t] + switch { + case !root && generated && newDefaults.object != nil: + parent.call = append(parent.call, newDefaults.object) + // if we will be generating the defaulter, it by definition is a covering + // defaulter, so we halt recursion + klog.V(6).Infof("the defaulter %s will be generated as an object defaulter", t.Name) + return parent + + case defaults.object != nil: + // object defaulters are always covering + parent.call = append(parent.call, defaults.object) + return parent + + case defaults.base != nil: + parent.call = append(parent.call, defaults.base) + // if the base function indicates it "covers" (it already includes defaulters) + // we can halt recursion + if checkTag(defaults.base.CommentLines, "covers") { + klog.V(6).Infof("the defaulter %s indicates it covers all sub generators", t.Name) + return parent + } + } + + // base has been added already, now add any additional defaulters defined for this object + parent.call = append(parent.call, defaults.additional...) + + // if the type already exists, don't build the tree for it and don't generate anything. + // This is used to avoid recursion for nested recursive types. + if c.currentlyBuildingTypes[t] { + return nil + } + // if type doesn't exist, mark it as existing + c.currentlyBuildingTypes[t] = true + + defer func() { + // The type will now acts as a parent, not a nested recursive type. + // We can now build the tree for it safely. + c.currentlyBuildingTypes[t] = false + }() + + switch t.Kind { + case types.Pointer: + if child := c.build(t.Elem, false); child != nil { + child.elem = true + parent.children = append(parent.children, *child) + } + case types.Slice, types.Array: + if child := c.build(t.Elem, false); child != nil { + child.index = true + if t.Elem.Kind == types.Pointer { + child.elem = true + } + parent.children = append(parent.children, *child) + } else if member := populateDefaultValue(nil, t.Elem, "", t.Elem.CommentLines, t.Elem.Name.Package); member != nil { + member.index = true + parent.children = append(parent.children, *member) + } + case types.Map: + if child := c.build(t.Elem, false); child != nil { + child.key = true + parent.children = append(parent.children, *child) + } else if member := populateDefaultValue(nil, t.Elem, "", t.Elem.CommentLines, t.Elem.Name.Package); member != nil { + member.key = true + parent.children = append(parent.children, *member) + } + + case types.Struct: + for _, field := range t.Members { + name := field.Name + if len(name) == 0 { + if field.Type.Kind == types.Pointer { + name = field.Type.Elem.Name.Name + } else { + name = field.Type.Name.Name + } + } + if child := c.build(field.Type, false); child != nil { + child.field = name + populateDefaultValue(child, field.Type, field.Tags, field.CommentLines, field.Type.Name.Package) + parent.children = append(parent.children, *child) + } else if member := populateDefaultValue(nil, field.Type, field.Tags, field.CommentLines, t.Name.Package); member != nil { + member.field = name + parent.children = append(parent.children, *member) + } + } + case types.Alias: + if child := c.build(t.Underlying, false); child != nil { + parent.children = append(parent.children, *child) + } + } + if len(parent.children) == 0 && len(parent.call) == 0 { + // klog.V(6).Infof("decided type %s needs no generation", t.Name) + return nil + } + return parent +} + +const ( + runtimePackagePath = "k8s.io/apimachinery/pkg/runtime" + conversionPackagePath = "k8s.io/apimachinery/pkg/conversion" +) + +// genDefaulter produces a file with a autogenerated conversions. +type genDefaulter struct { + generator.GoGenerator + typesPackage string + outputPackage string + peerPackages []string + newDefaulters defaulterFuncMap + existingDefaulters defaulterFuncMap + imports namer.ImportTracker + typesForInit []*types.Type +} + +func NewGenDefaulter(outputFilename, typesPackage, outputPackage string, existingDefaulters, newDefaulters defaulterFuncMap, peerPkgs []string) generator.Generator { + return &genDefaulter{ + GoGenerator: generator.GoGenerator{ + OutputFilename: outputFilename, + }, + typesPackage: typesPackage, + outputPackage: outputPackage, + peerPackages: peerPkgs, + newDefaulters: newDefaulters, + existingDefaulters: existingDefaulters, + imports: generator.NewImportTrackerForPackage(outputPackage), + typesForInit: make([]*types.Type, 0), + } +} + +func (g *genDefaulter) Namers(c *generator.Context) namer.NameSystems { + // Have the raw namer for this file track what it imports. + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *genDefaulter) isOtherPackage(pkg string) bool { + if pkg == g.outputPackage { + return false + } + if strings.HasSuffix(pkg, `"`+g.outputPackage+`"`) { + return false + } + return true +} + +func (g *genDefaulter) Filter(c *generator.Context, t *types.Type) bool { + defaults, ok := g.newDefaulters[t] + if !ok || defaults.object == nil { + return false + } + g.typesForInit = append(g.typesForInit, t) + return true +} + +func (g *genDefaulter) Imports(c *generator.Context) (imports []string) { + var importLines []string + for _, singleImport := range g.imports.ImportLines() { + if g.isOtherPackage(singleImport) { + importLines = append(importLines, singleImport) + } + } + return importLines +} + +func (g *genDefaulter) Init(c *generator.Context, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + + scheme := c.Universe.Type(types.Name{Package: runtimePackagePath, Name: "Scheme"}) + schemePtr := &types.Type{ + Kind: types.Pointer, + Elem: scheme, + } + sw.Do("// RegisterDefaults adds defaulters functions to the given scheme.\n", nil) + sw.Do("// Public to allow building arbitrary schemes.\n", nil) + sw.Do("// All generated defaulters are covering - they call all nested defaulters.\n", nil) + sw.Do("func RegisterDefaults(scheme $.|raw$) error {\n", schemePtr) + for _, t := range g.typesForInit { + args := defaultingArgsFromType(t) + sw.Do("scheme.AddTypeDefaultingFunc(&$.inType|raw${}, func(obj interface{}) { $.inType|objectdefaultfn$(obj.(*$.inType|raw$)) })\n", args) + } + sw.Do("return nil\n", nil) + sw.Do("}\n\n", nil) + return sw.Error() +} + +func (g *genDefaulter) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + if _, ok := g.newDefaulters[t]; !ok { + return nil + } + + klog.V(5).Infof("generating for type %v", t) + + callTree := newCallTreeForType(g.existingDefaulters, g.newDefaulters).build(t, true) + if callTree == nil { + klog.V(5).Infof(" no defaulters defined") + return nil + } + i := 0 + callTree.VisitInOrder(func(ancestors []*callNode, current *callNode) { + if ref := ¤t.defaultValue.SymbolReference; len(ref.Name) > 0 { + // Ensure package for symbol is imported in output generation + g.imports.AddSymbol(*ref) + + // Rewrite the fully qualified name using the local package name + // from the imports + ref.Package = g.imports.LocalNameOf(ref.Package) + } + + if len(current.call) == 0 { + return + } + path := callPath(append(ancestors, current)) + klog.V(5).Infof(" %d: %s", i, path) + i++ + }) + + sw := generator.NewSnippetWriter(w, c, "$", "$") + g.generateDefaulter(c, t, callTree, sw) + return sw.Error() +} + +func defaultingArgsFromType(inType *types.Type) generator.Args { + return generator.Args{ + "inType": inType, + } +} + +func (g *genDefaulter) generateDefaulter(c *generator.Context, inType *types.Type, callTree *callNode, sw *generator.SnippetWriter) { + sw.Do("func $.inType|objectdefaultfn$(in *$.inType|raw$) {\n", defaultingArgsFromType(inType)) + callTree.WriteMethod(c, "in", 0, nil, sw) + sw.Do("}\n\n", nil) +} + +// callNode represents an entry in a tree of Go type accessors - the path from the root to a leaf represents +// how in Go code an access would be performed. For example, if a defaulting function exists on a container +// lifecycle hook, to invoke that defaulter correctly would require this Go code: +// +// for i := range pod.Spec.Containers { +// o := &pod.Spec.Containers[i] +// if o.LifecycleHook != nil { +// SetDefaults_LifecycleHook(o.LifecycleHook) +// } +// } +// +// That would be represented by a call tree like: +// +// callNode +// field: "Spec" +// children: +// - field: "Containers" +// children: +// - index: true +// children: +// - field: "LifecycleHook" +// elem: true +// call: +// - SetDefaults_LifecycleHook +// +// which we can traverse to build that Go struct (you must call the field Spec, then Containers, then range over +// that field, then check whether the LifecycleHook field is nil, before calling SetDefaults_LifecycleHook on +// the pointer to that field). +type callNode struct { + // field is the name of the Go member to access + field string + // key is true if this is a map and we must range over the key and values + key bool + // index is true if this is a slice and we must range over the slice values + index bool + // elem is true if the previous elements refer to a pointer (typically just field) + elem bool + + // call is all of the functions that must be invoked on this particular node, in order + call []*types.Type + // children is the child call nodes that must also be traversed + children []callNode + + // defaultValue is the defaultValue of a callNode struct + // Only primitive types and pointer types are eligible to have a default value + defaultValue defaultValue + + // defaultIsPrimitive is used to determine how to assign the default value. + // Primitive types will be directly assigned while complex types will use JSON unmarshalling + defaultIsPrimitive bool + + // markerOnly is true if the callNode exists solely to fill in a default value + markerOnly bool + + // defaultType is the transitive underlying/element type of the node. + // The provided default value literal or reference is expected to be + // convertible to this type. + // + // e.g: + // node type = *string -> defaultType = string + // node type = StringPointerAlias -> defaultType = string + // Only populated if defaultIsPrimitive is true + defaultType *types.Type + + // defaultTopLevelType is the final type the value should resolve to + // This is in constrast with default type, which resolves aliases and pointers. + defaultTopLevelType *types.Type +} + +type defaultValue struct { + // The value was written directly in the marker comment and + // has been parsed as JSON + InlineConstant string + // The name of the symbol relative to the parsed package path + // i.e. k8s.io/pkg.apis.v1.Foo if from another package or simply `Foo` + // if within the same package. + SymbolReference types.Name +} + +func (d defaultValue) IsEmpty() bool { + resolved := d.Resolved() + return resolved == "" +} + +func (d defaultValue) Resolved() string { + if len(d.InlineConstant) > 0 { + return d.InlineConstant + } + return d.SymbolReference.String() +} + +// CallNodeVisitorFunc is a function for visiting a call tree. ancestors is the list of all parents +// of this node to the root of the tree - will be empty at the root. +type CallNodeVisitorFunc func(ancestors []*callNode, node *callNode) + +func (n *callNode) VisitInOrder(fn CallNodeVisitorFunc) { + n.visitInOrder(nil, fn) +} + +func (n *callNode) visitInOrder(ancestors []*callNode, fn CallNodeVisitorFunc) { + fn(ancestors, n) + ancestors = append(ancestors, n) + for i := range n.children { + n.children[i].visitInOrder(ancestors, fn) + } +} + +var ( + indexVariables = "ijklmnop" + localVariables = "abcdefgh" +) + +// varsForDepth creates temporary variables guaranteed to be unique within lexical Go scopes +// of this depth in a function. It uses canonical Go loop variables for the first 7 levels +// and then resorts to uglier prefixes. +func varsForDepth(depth int) (index, local string) { + if depth > len(indexVariables) { + index = fmt.Sprintf("i%d", depth) + } else { + index = indexVariables[depth : depth+1] + } + if depth > len(localVariables) { + local = fmt.Sprintf("local%d", depth) + } else { + local = localVariables[depth : depth+1] + } + return +} + +// writeCalls generates a list of function calls based on the calls field for the provided variable +// name and pointer. +func (n *callNode) writeCalls(varName string, isVarPointer bool, sw *generator.SnippetWriter) { + accessor := varName + if !isVarPointer { + accessor = "&" + accessor + } + for _, fn := range n.call { + sw.Do("$.fn|raw$($.var$)\n", generator.Args{ + "fn": fn, + "var": accessor, + }) + } +} + +func getTypeZeroValue(t string) (interface{}, error) { + defaultZero, ok := typeZeroValue[t] + if !ok { + return nil, fmt.Errorf("cannot find zero value for type %v in typeZeroValue", t) + } + + // To generate the code for empty string, they must be quoted + if defaultZero == "" { + defaultZero = strconv.Quote(defaultZero.(string)) + } + return defaultZero, nil +} + +func (n *callNode) writeDefaulter(c *generator.Context, varName string, index string, isVarPointer bool, sw *generator.SnippetWriter) { + if n.defaultValue.IsEmpty() { + return + } + + jsonUnmarshalType := c.Universe.Type(types.Name{Package: "encoding/json", Name: "Unmarshal"}) + + args := generator.Args{ + "defaultValue": n.defaultValue.Resolved(), + "varName": varName, + "index": index, + "varTopType": n.defaultTopLevelType, + "jsonUnmarshal": jsonUnmarshalType, + } + + variablePlaceholder := "" + + if n.index { + // Defaulting for array + variablePlaceholder = "$.varName$[$.index$]" + } else if n.key { + // Defaulting for map + variablePlaceholder = "$.varName$[$.index$]" + mapDefaultVar := args["index"].(string) + "_default" + args["mapDefaultVar"] = mapDefaultVar + } else { + // Defaulting for primitive type + variablePlaceholder = "$.varName$" + } + + // defaultIsPrimitive is true if the type or underlying type (in an array/map) is primitive + // or is a pointer to a primitive type + // (Eg: int, map[string]*string, []int) + if n.defaultIsPrimitive { + // If the default value is a primitive when the assigned type is a pointer + // keep using the address-of operator on the primitive value until the types match + if pointerPath := getPointerElementPath(n.defaultTopLevelType); len(pointerPath) > 0 { + // If the destination is a pointer, the last element in + // defaultDepth is the element type of the bottommost pointer: + // the base type of our default value. + destElemType := pointerPath[len(pointerPath)-1] + pointerArgs := args.WithArgs(generator.Args{ + "varDepth": len(pointerPath), + "baseElemType": destElemType, + }) + + sw.Do(fmt.Sprintf("if %s == nil {\n", variablePlaceholder), pointerArgs) + if len(n.defaultValue.InlineConstant) > 0 { + // If default value is a literal then it can be assigned via var stmt + sw.Do("var ptrVar$.varDepth$ $.baseElemType|raw$ = $.defaultValue$\n", pointerArgs) + } else { + // If default value is not a literal then it may need to be casted + // to the base type of the destination pointer + sw.Do("ptrVar$.varDepth$ := $.baseElemType|raw$($.defaultValue$)\n", pointerArgs) + } + + for i := len(pointerPath); i >= 1; i-- { + dest := fmt.Sprintf("ptrVar%d", i-1) + assignment := ":=" + if i == 1 { + // Last assignment is into the storage destination + dest = variablePlaceholder + assignment = "=" + } + + sourceType := "*" + destElemType.String() + if i == len(pointerPath) { + // Initial value is not a pointer + sourceType = destElemType.String() + } + destElemType = pointerPath[i-1] + + // Cannot include `dest` into args since its value may be + // `variablePlaceholder` which is a template, not a value + elementArgs := pointerArgs.WithArgs(generator.Args{ + "assignment": assignment, + "source": fmt.Sprintf("ptrVar%d", i), + "destElemType": destElemType, + }) + + // Skip cast if type is exact match + if destElemType.String() == sourceType { + sw.Do(fmt.Sprintf("%v $.assignment$ &$.source$\n", dest), elementArgs) + } else { + sw.Do(fmt.Sprintf("%v $.assignment$ (*$.destElemType|raw$)(&$.source$)\n", dest), elementArgs) + } + } + } else { + // For primitive types, nil checks cannot be used and the zero value must be determined + defaultZero, err := getTypeZeroValue(n.defaultType.String()) + if err != nil { + klog.Error(err) + } + args["defaultZero"] = defaultZero + + sw.Do(fmt.Sprintf("if %s == $.defaultZero$ {\n", variablePlaceholder), args) + + if len(n.defaultValue.InlineConstant) > 0 { + sw.Do(fmt.Sprintf("%s = $.defaultValue$", variablePlaceholder), args) + } else { + sw.Do(fmt.Sprintf("%s = $.varTopType|raw$($.defaultValue$)", variablePlaceholder), args) + } + } + } else { + sw.Do(fmt.Sprintf("if %s == nil {\n", variablePlaceholder), args) + // Map values are not directly addressable and we need a temporary variable to do json unmarshalling + // This applies to maps with non-primitive values (eg: map[string]SubStruct) + if n.key { + sw.Do("$.mapDefaultVar$ := $.varName$[$.index$]\n", args) + sw.Do("if err := $.jsonUnmarshal|raw$([]byte(`$.defaultValue$`), &$.mapDefaultVar$); err != nil {\n", args) + } else { + variablePointer := variablePlaceholder + if !isVarPointer { + variablePointer = "&" + variablePointer + } + sw.Do(fmt.Sprintf("if err := $.jsonUnmarshal|raw$([]byte(`$.defaultValue$`), %s); err != nil {\n", variablePointer), args) + } + sw.Do("panic(err)\n", nil) + sw.Do("}\n", nil) + if n.key { + sw.Do("$.varName$[$.index$] = $.mapDefaultVar$\n", args) + } + } + sw.Do("}\n", nil) +} + +// WriteMethod performs an in-order traversal of the calltree, generating loops and if blocks as necessary +// to correctly turn the call tree into a method body that invokes all calls on all child nodes of the call tree. +// Depth is used to generate local variables at the proper depth. +func (n *callNode) WriteMethod(c *generator.Context, varName string, depth int, ancestors []*callNode, sw *generator.SnippetWriter) { + // if len(n.call) > 0 { + // sw.Do(fmt.Sprintf("// %s\n", callPath(append(ancestors, n)).String()), nil) + // } + + if len(n.field) > 0 { + varName = varName + "." + n.field + } + + index, local := varsForDepth(depth) + vars := generator.Args{ + "index": index, + "local": local, + "var": varName, + } + + isPointer := n.elem && !n.index + if isPointer && len(ancestors) > 0 { + sw.Do("if $.var$ != nil {\n", vars) + } + + switch { + case n.index: + sw.Do("for $.index$ := range $.var$ {\n", vars) + if !n.markerOnly { + if n.elem { + sw.Do("$.local$ := $.var$[$.index$]\n", vars) + } else { + sw.Do("$.local$ := &$.var$[$.index$]\n", vars) + } + } + + n.writeDefaulter(c, varName, index, isPointer, sw) + n.writeCalls(local, true, sw) + for i := range n.children { + n.children[i].WriteMethod(c, local, depth+1, append(ancestors, n), sw) + } + sw.Do("}\n", nil) + case n.key: + if !n.defaultValue.IsEmpty() { + // Map keys are typed and cannot share the same index variable as arrays and other maps + index = index + "_" + ancestors[len(ancestors)-1].field + vars["index"] = index + sw.Do("for $.index$ := range $.var$ {\n", vars) + n.writeDefaulter(c, varName, index, isPointer, sw) + sw.Do("}\n", nil) + } + default: + n.writeDefaulter(c, varName, index, isPointer, sw) + n.writeCalls(varName, isPointer, sw) + for i := range n.children { + n.children[i].WriteMethod(c, varName, depth, append(ancestors, n), sw) + } + } + + if isPointer && len(ancestors) > 0 { + sw.Do("}\n", nil) + } +} + +type callPath []*callNode + +// String prints a representation of a callPath that roughly approximates what a Go accessor +// would look like. Used for debugging only. +func (path callPath) String() string { + if len(path) == 0 { + return "" + } + var parts []string + for _, p := range path { + last := len(parts) - 1 + switch { + case p.elem: + if len(parts) > 0 { + parts[last] = "*" + parts[last] + } else { + parts = append(parts, "*") + } + case p.index: + if len(parts) > 0 { + parts[last] += "[i]" + } else { + parts = append(parts, "[i]") + } + case p.key: + if len(parts) > 0 { + parts[last] += "[key]" + } else { + parts = append(parts, "[key]") + } + default: + if len(p.field) > 0 { + parts = append(parts, p.field) + } else { + parts = append(parts, "") + } + } + } + var calls []string + for _, fn := range path[len(path)-1].call { + calls = append(calls, fn.Name.String()) + } + if len(calls) == 0 { + calls = append(calls, "") + } + + return strings.Join(parts, ".") + " calls " + strings.Join(calls, ", ") +} diff --git a/code-generator/cmd/defaulter-gen/main.go b/code-generator/cmd/defaulter-gen/main.go new file mode 100644 index 000000000..d57ca0666 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/main.go @@ -0,0 +1,83 @@ +/* +Copyright 2016 The Kubernetes 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. +*/ + +// defaulter-gen is a tool for auto-generating Defaulter functions. +// +// Given a list of input directories, it will scan for top level types +// and generate efficient defaulters for an entire object from the sum +// of the SetDefault_* methods contained in the object tree. +// +// Generation is governed by comment tags in the source. Any package may +// request defaulter generation by including one or more comment tags at +// the package comment level: +// +// // +k8s:defaulter-gen= +// +// which will create defaulters for any type that contains the provided +// field name (if the type has defaulters). Any type may request explicit +// defaulting by providing the comment tag: +// +// // +k8s:defaulter-gen=true|false +// +// An existing defaulter method (`SetDefaults_TYPE`) can provide the +// comment tag: +// +// // +k8s:defaulter-gen=covers +// +// to indicate that the defaulter does not or should not call any nested +// defaulters. +package main + +import ( + "flag" + + "github.com/spf13/pflag" + "k8s.io/code-generator/cmd/defaulter-gen/args" + "k8s.io/code-generator/cmd/defaulter-gen/generators" + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/klog/v2" +) + +func main() { + klog.InitFlags(nil) + args := args.New() + + args.AddFlags(pflag.CommandLine) + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + if err := args.Validate(); err != nil { + klog.Fatalf("Error: %v", err) + } + + myTargets := func(context *generator.Context) []generator.Target { + return generators.GetTargets(context, args) + } + + // Run it. + if err := gengo.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + myTargets, + gengo.StdBuildTag, + pflag.Args(), + ); err != nil { + klog.Fatalf("Error: %v", err) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/code-generator/cmd/defaulter-gen/output_tests/empty/doc.go b/code-generator/cmd/defaulter-gen/output_tests/empty/doc.go new file mode 100644 index 000000000..5dc6bba16 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/empty/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 The Kubernetes 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. +*/ + +// +k8s:defaulter-gen=covers + +// This is a test package. +package empty // import "k8s.io/code-generator/cmd/defaulter-gen/output_tests/empty" diff --git a/code-generator/cmd/defaulter-gen/output_tests/empty/type.go b/code-generator/cmd/defaulter-gen/output_tests/empty/type.go new file mode 100644 index 000000000..707e6fa4a --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/empty/type.go @@ -0,0 +1,29 @@ +/* +Copyright 2018 The Kubernetes 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 empty + +// Only test +type Ttest struct { + BoolField bool + IntField int + StringField string + FloatField float64 +} + +type TypeMeta struct { + Fortest bool +} diff --git a/code-generator/cmd/defaulter-gen/output_tests/empty/zz_generated.defaults.go b/code-generator/cmd/defaulter-gen/output_tests/empty/zz_generated.defaults.go new file mode 100644 index 000000000..4c6ab363b --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/empty/zz_generated.defaults.go @@ -0,0 +1,33 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package empty + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/code-generator/cmd/defaulter-gen/output_tests/generate.go b/code-generator/cmd/defaulter-gen/output_tests/generate.go new file mode 100644 index 000000000..486ddacf8 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/generate.go @@ -0,0 +1,27 @@ +//go:build !ignore_autogenerated + +/* +Copyright 2024 The Kubernetes 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. +*/ + +// Ignore this file to prevent zz_generated for this package + +//go:generate go run k8s.io/code-generator/cmd/defaulter-gen --output-file zz_generated.defaults.go --go-header-file=../../../examples/hack/boilerplate.go.txt k8s.io/code-generator/cmd/defaulter-gen/output_tests/... +package outputtests + +import ( + // For go-generate + _ "k8s.io/code-generator/cmd/defaulter-gen/generators" +) diff --git a/code-generator/cmd/defaulter-gen/output_tests/marker/defaults.go b/code-generator/cmd/defaulter-gen/output_tests/marker/defaults.go new file mode 100644 index 000000000..7e27d5412 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/marker/defaults.go @@ -0,0 +1,32 @@ +/* +Copyright 2020 The Kubernetes 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 marker + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +//nolint:unused +func addDefaultingFuncs(scheme *runtime.Scheme) error { + return RegisterDefaults(scheme) +} + +func SetDefaults_DefaultedWithFunction(obj *DefaultedWithFunction) { + if obj.S1 == "" { + obj.S1 = "default_function" + } +} diff --git a/code-generator/cmd/defaulter-gen/output_tests/marker/doc.go b/code-generator/cmd/defaulter-gen/output_tests/marker/doc.go new file mode 100644 index 000000000..b99ba6a6d --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/marker/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2020 The Kubernetes 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. +*/ + +// +k8s:defaulter-gen=TypeMeta + +// This is a test package. +package marker // import "k8s.io/code-generator/cmd/defaulter-gen/output_tests/marker" diff --git a/code-generator/cmd/defaulter-gen/output_tests/marker/external/constant.go b/code-generator/cmd/defaulter-gen/output_tests/marker/external/constant.go new file mode 100644 index 000000000..d04b8e02b --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/marker/external/constant.go @@ -0,0 +1,20 @@ +/* +Copyright 2024 The Kubernetes 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 external + +// Used for test with multiple packages of the same name +const AConstant string = "AConstantString" diff --git a/code-generator/cmd/defaulter-gen/output_tests/marker/external/external/constant.go b/code-generator/cmd/defaulter-gen/output_tests/marker/external/external/constant.go new file mode 100644 index 000000000..494da1054 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/marker/external/external/constant.go @@ -0,0 +1,20 @@ +/* +Copyright 2024 The Kubernetes 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 external + +// Used for test with multiple packages of the same name +const AnotherConstant string = "AnotherConstantString" diff --git a/code-generator/cmd/defaulter-gen/output_tests/marker/external2/type.go b/code-generator/cmd/defaulter-gen/output_tests/marker/external2/type.go new file mode 100644 index 000000000..df0b94bcb --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/marker/external2/type.go @@ -0,0 +1,19 @@ +/* +Copyright 2024 The Kubernetes 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 external2 + +type String string diff --git a/code-generator/cmd/defaulter-gen/output_tests/marker/external3/constant.go b/code-generator/cmd/defaulter-gen/output_tests/marker/external3/constant.go new file mode 100644 index 000000000..a97f46984 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/marker/external3/constant.go @@ -0,0 +1,21 @@ +/* +Copyright 2024 The Kubernetes 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 external3 + +import "k8s.io/code-generator/cmd/defaulter-gen/output_tests/marker/external2" + +type StringPointer *external2.String diff --git a/code-generator/cmd/defaulter-gen/output_tests/marker/fake_deepcopy_conversion.go b/code-generator/cmd/defaulter-gen/output_tests/marker/fake_deepcopy_conversion.go new file mode 100644 index 000000000..5ccc12b63 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/marker/fake_deepcopy_conversion.go @@ -0,0 +1,107 @@ +/* +Copyright 2020 The Kubernetes 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 marker + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +func (in *Defaulted) DeepCopy() *Defaulted { + if in == nil { + return nil + } + out := new(Defaulted) + in.DeepCopyInto(out) + return out +} + +func (in *Defaulted) DeepCopyInto(out *Defaulted) { + *out = *in +} + +func (in *Defaulted) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +func (in *DefaultedOmitempty) DeepCopy() *DefaultedOmitempty { + if in == nil { + return nil + } + out := new(DefaultedOmitempty) + in.DeepCopyInto(out) + return out +} + +func (in *DefaultedOmitempty) DeepCopyInto(out *DefaultedOmitempty) { + *out = *in +} + +func (in *DefaultedOmitempty) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +func (in *DefaultedWithFunction) DeepCopy() *DefaultedWithFunction { + if in == nil { + return nil + } + out := new(DefaultedWithFunction) + in.DeepCopyInto(out) + return out +} + +func (in *DefaultedWithFunction) DeepCopyInto(out *DefaultedWithFunction) { + *out = *in +} + +func (in *DefaultedWithFunction) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +func (in *Defaulted) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } +func (in *DefaultedOmitempty) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } +func (in *DefaultedWithFunction) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } +func (in *DefaultedWithReference) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } + +func (in *DefaultedWithReference) DeepCopy() *DefaultedWithReference { + if in == nil { + return nil + } + out := new(DefaultedWithReference) + in.DeepCopyInto(out) + return out +} + +func (in *DefaultedWithReference) DeepCopyInto(out *DefaultedWithReference) { + *out = *in +} + +func (in *DefaultedWithReference) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/code-generator/cmd/defaulter-gen/output_tests/marker/marker_test.go b/code-generator/cmd/defaulter-gen/output_tests/marker/marker_test.go new file mode 100644 index 000000000..003ac06cb --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/marker/marker_test.go @@ -0,0 +1,412 @@ +/* +Copyright 2020 The Kubernetes 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 marker + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + + "k8s.io/code-generator/cmd/defaulter-gen/output_tests/marker/external" + externalexternal "k8s.io/code-generator/cmd/defaulter-gen/output_tests/marker/external/external" + "k8s.io/code-generator/cmd/defaulter-gen/output_tests/marker/external2" + "k8s.io/code-generator/cmd/defaulter-gen/output_tests/marker/external3" +) + +func getPointerFromString(s string) *string { + return &s +} + +var ( + defaultInt32 int32 = 32 + defaultInt64 int64 = 64 +) + +func Test_Marker(t *testing.T) { + testcases := []struct { + name string + in Defaulted + out Defaulted + }{ + { + name: "default", + in: Defaulted{}, + out: Defaulted{ + StringDefault: "bar", + StringEmptyDefault: "", + StringEmpty: "", + StringPointer: getPointerFromString("default"), + Int64: &defaultInt64, + Int32: &defaultInt32, + IntDefault: 1, + IntEmptyDefault: 0, + IntEmpty: 0, + FloatDefault: 0.5, + FloatEmptyDefault: 0.0, + FloatEmpty: 0.0, + List: []Item{ + getPointerFromString("foo"), + getPointerFromString("bar"), + }, + Sub: &SubStruct{ + S: "foo", + I: 5, + }, + OtherSub: SubStruct{ + S: "", + I: 1, + }, + StructList: []SubStruct{ + { + S: "foo1", + I: 1, + }, + { + S: "foo2", + I: 1, + }, + }, + PtrStructList: []*SubStruct{ + { + S: "foo1", + I: 1, + }, + { + S: "foo2", + I: 1, + }, + }, + StringList: []string{ + "foo", + }, + Map: map[string]Item{ + "foo": getPointerFromString("bar"), + }, + StructMap: map[string]SubStruct{ + "foo": { + S: "string", + I: 1, + }, + }, + PtrStructMap: map[string]*SubStruct{ + "foo": { + S: "string", + I: 1, + }, + }, + AliasPtr: getPointerFromString("banana"), + }, + }, + { + name: "values-omitempty", + in: Defaulted{ + StringDefault: "changed", + IntDefault: 5, + }, + out: Defaulted{ + StringDefault: "changed", + StringEmptyDefault: "", + StringEmpty: "", + StringPointer: getPointerFromString("default"), + Int64: &defaultInt64, + Int32: &defaultInt32, + IntDefault: 5, + IntEmptyDefault: 0, + IntEmpty: 0, + FloatDefault: 0.5, + FloatEmptyDefault: 0.0, + FloatEmpty: 0.0, + List: []Item{ + getPointerFromString("foo"), + getPointerFromString("bar"), + }, + Sub: &SubStruct{ + S: "foo", + I: 5, + }, + StructList: []SubStruct{ + { + S: "foo1", + I: 1, + }, + { + S: "foo2", + I: 1, + }, + }, + PtrStructList: []*SubStruct{ + { + S: "foo1", + I: 1, + }, + { + S: "foo2", + I: 1, + }, + }, + StringList: []string{ + "foo", + }, + OtherSub: SubStruct{ + S: "", + I: 1, + }, + Map: map[string]Item{ + "foo": getPointerFromString("bar"), + }, + StructMap: map[string]SubStruct{ + "foo": { + S: "string", + I: 1, + }, + }, + PtrStructMap: map[string]*SubStruct{ + "foo": { + S: "string", + I: 1, + }, + }, + AliasPtr: getPointerFromString("banana"), + }, + }, + { + name: "lists", + in: Defaulted{ + List: []Item{ + nil, + getPointerFromString("bar"), + }, + }, + out: Defaulted{ + StringDefault: "bar", + StringEmptyDefault: "", + StringEmpty: "", + StringPointer: getPointerFromString("default"), + Int64: &defaultInt64, + Int32: &defaultInt32, + IntDefault: 1, + IntEmptyDefault: 0, + IntEmpty: 0, + FloatDefault: 0.5, + FloatEmptyDefault: 0.0, + FloatEmpty: 0.0, + List: []Item{ + getPointerFromString("apple"), + getPointerFromString("bar"), + }, + Sub: &SubStruct{ + S: "foo", + I: 5, + }, + StructList: []SubStruct{ + { + S: "foo1", + I: 1, + }, + { + S: "foo2", + I: 1, + }, + }, + PtrStructList: []*SubStruct{ + { + S: "foo1", + I: 1, + }, + { + S: "foo2", + I: 1, + }, + }, + StringList: []string{ + "foo", + }, + OtherSub: SubStruct{ + S: "", + I: 1, + }, + Map: map[string]Item{ + "foo": getPointerFromString("bar"), + }, + StructMap: map[string]SubStruct{ + "foo": { + S: "string", + I: 1, + }, + }, + PtrStructMap: map[string]*SubStruct{ + "foo": { + S: "string", + I: 1, + }, + }, + AliasPtr: getPointerFromString("banana"), + }, + }, + { + name: "stringmap", + in: Defaulted{ + Map: map[string]Item{ + "foo": nil, + "bar": getPointerFromString("banana"), + }, + }, + out: Defaulted{ + StringDefault: "bar", + StringEmptyDefault: "", + StringEmpty: "", + StringPointer: getPointerFromString("default"), + Int64: &defaultInt64, + Int32: &defaultInt32, + IntDefault: 1, + IntEmptyDefault: 0, + IntEmpty: 0, + FloatDefault: 0.5, + FloatEmptyDefault: 0.0, + FloatEmpty: 0.0, + List: []Item{ + getPointerFromString("foo"), + getPointerFromString("bar"), + }, + Sub: &SubStruct{ + S: "foo", + I: 5, + }, + StructList: []SubStruct{ + { + S: "foo1", + I: 1, + }, + { + S: "foo2", + I: 1, + }, + }, + PtrStructList: []*SubStruct{ + { + S: "foo1", + I: 1, + }, + { + S: "foo2", + I: 1, + }, + }, + StringList: []string{ + "foo", + }, + OtherSub: SubStruct{ + S: "", + I: 1, + }, + Map: map[string]Item{ + "foo": getPointerFromString("apple"), + "bar": getPointerFromString("banana"), + }, + StructMap: map[string]SubStruct{ + "foo": { + S: "string", + I: 1, + }, + }, + PtrStructMap: map[string]*SubStruct{ + "foo": { + S: "string", + I: 1, + }, + }, + AliasPtr: getPointerFromString("banana"), + }, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + SetObjectDefaults_Defaulted(&tc.in) + if diff := cmp.Diff(tc.out, tc.in); len(diff) > 0 { + t.Errorf("Error: Expected and actual output are different \n %s\n", diff) + } + }) + } +} + +func Test_DefaultingFunction(t *testing.T) { + in := DefaultedWithFunction{} + SetObjectDefaults_DefaultedWithFunction(&in) + out := DefaultedWithFunction{ + S1: "default_function", + S2: "default_marker", + } + if diff := cmp.Diff(out, in); len(diff) > 0 { + t.Errorf("Error: Expected and actual output are different \n %s\n", diff) + } + +} + +func Test_DefaultingReference(t *testing.T) { + dv := DefaultedValueItem(SomeValue) + SomeDefault := SomeDefault + SomeValue := SomeValue + + ptrVar9 := string(SomeValue) + ptrVar8 := &ptrVar9 + ptrVar7 := (*B1)(&ptrVar8) + ptrVar6 := (*B2)(&ptrVar7) + ptrVar5 := &ptrVar6 + ptrVar4 := &ptrVar5 + ptrVar3 := &ptrVar4 + ptrVar2 := (*B3)(&ptrVar3) + ptrVar1 := &ptrVar2 + + var external2Str = external2.String(SomeValue) + + testcases := []struct { + name string + in DefaultedWithReference + out DefaultedWithReference + }{ + { + name: "default", + in: DefaultedWithReference{}, + out: DefaultedWithReference{ + AliasPointerInside: Item(&SomeDefault), + AliasOverride: Item(&SomeDefault), + AliasConvertDefaultPointer: &dv, + AliasPointerDefault: &dv, + PointerAliasDefault: Item(getPointerFromString("apple")), + AliasNonPointer: SomeValue, + AliasPointer: &SomeValue, + SymbolReference: SomeDefault, + SameNamePackageSymbolReference1: external.AConstant, + SameNamePackageSymbolReference2: externalexternal.AnotherConstant, + PointerConversion: (*B4)(&ptrVar1), + PointerConversionValue: (B4)(ptrVar1), + FullyQualifiedLocalSymbol: string(SomeValue), + ImportFromAliasCast: external3.StringPointer(&external2Str), + }, + }, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + SetObjectDefaults_DefaultedWithReference(&tc.in) + if diff := cmp.Diff(tc.out, tc.in); len(diff) > 0 { + t.Errorf("Error: Expected and actual output are different \n %s\n", diff) + } + }) + } +} diff --git a/code-generator/cmd/defaulter-gen/output_tests/marker/type.go b/code-generator/cmd/defaulter-gen/output_tests/marker/type.go new file mode 100644 index 000000000..0658ba217 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/marker/type.go @@ -0,0 +1,265 @@ +/* +Copyright 2020 The Kubernetes 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 marker + +import ( + "k8s.io/code-generator/cmd/defaulter-gen/output_tests/empty" + "k8s.io/code-generator/cmd/defaulter-gen/output_tests/marker/external3" +) + +type Defaulted struct { + empty.TypeMeta + + // +default="bar" + StringDefault string + + // Default is forced to empty string + // Specifying the default is a no-op + // +default="" + StringEmptyDefault string + + // Not specifying a default still defaults for non-omitempty + StringEmpty string + + // +default="default" + StringPointer *string + + // +default=64 + Int64 *int64 + + // +default=32 + Int32 *int32 + + // +default=1 + IntDefault int + + // +default=0 + IntEmptyDefault int + + // Default is forced to 0 + IntEmpty int + + // +default=0.5 + FloatDefault float64 + + // +default=0.0 + FloatEmptyDefault float64 + + FloatEmpty float64 + + // +default=["foo", "bar"] + List []Item + // +default={"s": "foo", "i": 5} + Sub *SubStruct + + //+default=[{"s": "foo1", "i": 1}, {"s": "foo2"}] + StructList []SubStruct + + //+default=[{"s": "foo1", "i": 1}, {"s": "foo2"}] + PtrStructList []*SubStruct + + //+default=["foo"] + StringList []string + + // Default is forced to empty struct + OtherSub SubStruct + + // +default={"foo": "bar"} + Map map[string]Item + + // +default={"foo": {"S": "string", "I": 1}} + StructMap map[string]SubStruct + + // +default={"foo": {"S": "string", "I": 1}} + PtrStructMap map[string]*SubStruct + + // A default specified here overrides the default for the Item type + // +default="banana" + AliasPtr Item +} + +type DefaultedOmitempty struct { + empty.TypeMeta `json:",omitempty"` + + // +default="bar" + StringDefault string `json:",omitempty"` + + // Default is forced to empty string + // Specifying the default is a no-op + // +default="" + StringEmptyDefault string `json:",omitempty"` + + // Not specifying a default still defaults for non-omitempty + StringEmpty string `json:",omitempty"` + + // +default="default" + StringPointer *string `json:",omitempty"` + + // +default=64 + Int64 *int64 `json:",omitempty"` + + // +default=32 + Int32 *int32 `json:",omitempty"` + + // +default=1 + IntDefault int `json:",omitempty"` + + // +default=0 + IntEmptyDefault int `json:",omitempty"` + + // Default is forced to 0 + IntEmpty int `json:",omitempty"` + + // +default=0.5 + FloatDefault float64 `json:",omitempty"` + + // +default=0.0 + FloatEmptyDefault float64 `json:",omitempty"` + + FloatEmpty float64 `json:",omitempty"` + + // +default=["foo", "bar"] + List []Item `json:",omitempty"` + // +default={"s": "foo", "i": 5} + Sub *SubStruct `json:",omitempty"` + + //+default=[{"s": "foo1", "i": 1}, {"s": "foo2"}] + StructList []SubStruct `json:",omitempty"` + + //+default=[{"s": "foo1", "i": 1}, {"s": "foo2"}] + PtrStructList []*SubStruct `json:",omitempty"` + + //+default=["foo"] + StringList []string `json:",omitempty"` + + // Default is forced to empty struct + OtherSub SubStruct `json:",omitempty"` + + // +default={"foo": "bar"} + Map map[string]Item `json:",omitempty"` + + // +default={"foo": {"S": "string", "I": 1}} + StructMap map[string]SubStruct `json:",omitempty"` + + // +default={"foo": {"S": "string", "I": 1}} + PtrStructMap map[string]*SubStruct `json:",omitempty"` + + // A default specified here overrides the default for the Item type + // +default="banana" + AliasPtr Item `json:",omitempty"` +} + +const SomeDefault = "ACoolConstant" + +// +default="apple" +type Item *string + +type ValueItem string + +// +default=ref(SomeValue) +type DefaultedValueItem ValueItem +type PointerValueItem *DefaultedValueItem + +type ItemDefaultWiped Item + +const SomeValue ValueItem = "Value" + +type SubStruct struct { + S string + // +default=1 + I int `json:"I,omitempty"` +} + +type DefaultedWithFunction struct { + empty.TypeMeta + // +default="default_marker" + S1 string `json:"S1,omitempty"` + // +default="default_marker" + S2 string `json:"S2,omitempty"` +} + +type DefaultedWithReference struct { + empty.TypeMeta + + // Shows that if we have an alias that is a pointer and have a default + // that is a value convertible to that pointer we can still use it + // +default=ref(SomeValue) + AliasConvertDefaultPointer PointerValueItem + + // Shows that default defined on a nested type is not respected through + // an alias + AliasWipedDefault ItemDefaultWiped + + // A default defined on a pointer-valued alias is respected + PointerAliasDefault Item + + // Can have alias that is a pointer to type of constant + // +default=ref(SomeDefault) + AliasPointerInside Item + + // Can override default specified on an alias + // +default=ref(SomeDefault) + AliasOverride Item + + // Type-level default is not respected unless a pointer + AliasNonPointerDefault DefaultedValueItem `json:",omitempty"` + + // Type-level default is not respected unless a pointer + AliasPointerDefault *DefaultedValueItem + + // Can have value typed alias + // +default=ref(SomeValue) + AliasNonPointer ValueItem `json:",omitempty"` + + // Can have a pointer to an alias whose default is a non-pointer value + // +default=ref(SomeValue) + AliasPointer *ValueItem `json:",omitempty"` + + // Basic ref usage example + // +default=ref(SomeDefault) + SymbolReference string `json:",omitempty"` + + // +default=ref(k8s.io/code-generator/cmd/defaulter-gen/output_tests/marker/external.AConstant) + SameNamePackageSymbolReference1 string `json:",omitempty"` + + // +default=ref(k8s.io/code-generator/cmd/defaulter-gen/output_tests/marker/external/external.AnotherConstant) + SameNamePackageSymbolReference2 string `json:",omitempty"` + + // Should convert ValueItem -> string then up to B4 through addressOf and + // casting + // +default=ref(SomeValue) + PointerConversion *B4 + + // +default=ref(SomeValue) + PointerConversionValue B4 + + // +default=ref(k8s.io/code-generator/cmd/defaulter-gen/output_tests/marker.SomeValue) + FullyQualifiedLocalSymbol string + + // Construction of external3.StringPointer requires importing external2 + // Test that generator can handle it + // +default=ref(SomeValue) + ImportFromAliasCast external3.StringPointer +} + +// Super complicated hierarchy of aliases which includes multiple pointers, +// and sibling types. +type B0 *string +type B1 B0 +type B2 *B1 +type B3 ****B2 +type B4 **B3 diff --git a/code-generator/cmd/defaulter-gen/output_tests/marker/zz_generated.defaults.go b/code-generator/cmd/defaulter-gen/output_tests/marker/zz_generated.defaults.go new file mode 100644 index 000000000..0add63d4c --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/marker/zz_generated.defaults.go @@ -0,0 +1,325 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package marker + +import ( + json "encoding/json" + + runtime "k8s.io/apimachinery/pkg/runtime" + external "k8s.io/code-generator/cmd/defaulter-gen/output_tests/marker/external" + externalexternal "k8s.io/code-generator/cmd/defaulter-gen/output_tests/marker/external/external" + external2 "k8s.io/code-generator/cmd/defaulter-gen/output_tests/marker/external2" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + scheme.AddTypeDefaultingFunc(&Defaulted{}, func(obj interface{}) { SetObjectDefaults_Defaulted(obj.(*Defaulted)) }) + scheme.AddTypeDefaultingFunc(&DefaultedOmitempty{}, func(obj interface{}) { SetObjectDefaults_DefaultedOmitempty(obj.(*DefaultedOmitempty)) }) + scheme.AddTypeDefaultingFunc(&DefaultedWithFunction{}, func(obj interface{}) { SetObjectDefaults_DefaultedWithFunction(obj.(*DefaultedWithFunction)) }) + scheme.AddTypeDefaultingFunc(&DefaultedWithReference{}, func(obj interface{}) { SetObjectDefaults_DefaultedWithReference(obj.(*DefaultedWithReference)) }) + return nil +} + +func SetObjectDefaults_Defaulted(in *Defaulted) { + if in.StringDefault == "" { + in.StringDefault = "bar" + } + if in.StringPointer == nil { + var ptrVar1 string = "default" + in.StringPointer = &ptrVar1 + } + if in.Int64 == nil { + var ptrVar1 int64 = 64 + in.Int64 = &ptrVar1 + } + if in.Int32 == nil { + var ptrVar1 int32 = 32 + in.Int32 = &ptrVar1 + } + if in.IntDefault == 0 { + in.IntDefault = 1 + } + if in.FloatDefault == 0 { + in.FloatDefault = 0.5 + } + if in.List == nil { + if err := json.Unmarshal([]byte(`["foo", "bar"]`), &in.List); err != nil { + panic(err) + } + } + for i := range in.List { + if in.List[i] == nil { + var ptrVar1 string = "apple" + in.List[i] = &ptrVar1 + } + } + if in.Sub == nil { + if err := json.Unmarshal([]byte(`{"s": "foo", "i": 5}`), &in.Sub); err != nil { + panic(err) + } + } + if in.Sub != nil { + if in.Sub.I == 0 { + in.Sub.I = 1 + } + } + if in.StructList == nil { + if err := json.Unmarshal([]byte(`[{"s": "foo1", "i": 1}, {"s": "foo2"}]`), &in.StructList); err != nil { + panic(err) + } + } + for i := range in.StructList { + a := &in.StructList[i] + if a.I == 0 { + a.I = 1 + } + } + if in.PtrStructList == nil { + if err := json.Unmarshal([]byte(`[{"s": "foo1", "i": 1}, {"s": "foo2"}]`), &in.PtrStructList); err != nil { + panic(err) + } + } + for i := range in.PtrStructList { + a := in.PtrStructList[i] + if a != nil { + if a.I == 0 { + a.I = 1 + } + } + } + if in.StringList == nil { + if err := json.Unmarshal([]byte(`["foo"]`), &in.StringList); err != nil { + panic(err) + } + } + if in.OtherSub.I == 0 { + in.OtherSub.I = 1 + } + if in.Map == nil { + if err := json.Unmarshal([]byte(`{"foo": "bar"}`), &in.Map); err != nil { + panic(err) + } + } + for i_Map := range in.Map { + if in.Map[i_Map] == nil { + var ptrVar1 string = "apple" + in.Map[i_Map] = &ptrVar1 + } + } + if in.StructMap == nil { + if err := json.Unmarshal([]byte(`{"foo": {"S": "string", "I": 1}}`), &in.StructMap); err != nil { + panic(err) + } + } + if in.PtrStructMap == nil { + if err := json.Unmarshal([]byte(`{"foo": {"S": "string", "I": 1}}`), &in.PtrStructMap); err != nil { + panic(err) + } + } + if in.AliasPtr == nil { + var ptrVar1 string = "banana" + in.AliasPtr = &ptrVar1 + } +} + +func SetObjectDefaults_DefaultedOmitempty(in *DefaultedOmitempty) { + if in.StringDefault == "" { + in.StringDefault = "bar" + } + if in.StringPointer == nil { + var ptrVar1 string = "default" + in.StringPointer = &ptrVar1 + } + if in.Int64 == nil { + var ptrVar1 int64 = 64 + in.Int64 = &ptrVar1 + } + if in.Int32 == nil { + var ptrVar1 int32 = 32 + in.Int32 = &ptrVar1 + } + if in.IntDefault == 0 { + in.IntDefault = 1 + } + if in.FloatDefault == 0 { + in.FloatDefault = 0.5 + } + if in.List == nil { + if err := json.Unmarshal([]byte(`["foo", "bar"]`), &in.List); err != nil { + panic(err) + } + } + for i := range in.List { + if in.List[i] == nil { + var ptrVar1 string = "apple" + in.List[i] = &ptrVar1 + } + } + if in.Sub == nil { + if err := json.Unmarshal([]byte(`{"s": "foo", "i": 5}`), &in.Sub); err != nil { + panic(err) + } + } + if in.Sub != nil { + if in.Sub.I == 0 { + in.Sub.I = 1 + } + } + if in.StructList == nil { + if err := json.Unmarshal([]byte(`[{"s": "foo1", "i": 1}, {"s": "foo2"}]`), &in.StructList); err != nil { + panic(err) + } + } + for i := range in.StructList { + a := &in.StructList[i] + if a.I == 0 { + a.I = 1 + } + } + if in.PtrStructList == nil { + if err := json.Unmarshal([]byte(`[{"s": "foo1", "i": 1}, {"s": "foo2"}]`), &in.PtrStructList); err != nil { + panic(err) + } + } + for i := range in.PtrStructList { + a := in.PtrStructList[i] + if a != nil { + if a.I == 0 { + a.I = 1 + } + } + } + if in.StringList == nil { + if err := json.Unmarshal([]byte(`["foo"]`), &in.StringList); err != nil { + panic(err) + } + } + if in.OtherSub.I == 0 { + in.OtherSub.I = 1 + } + if in.Map == nil { + if err := json.Unmarshal([]byte(`{"foo": "bar"}`), &in.Map); err != nil { + panic(err) + } + } + for i_Map := range in.Map { + if in.Map[i_Map] == nil { + var ptrVar1 string = "apple" + in.Map[i_Map] = &ptrVar1 + } + } + if in.StructMap == nil { + if err := json.Unmarshal([]byte(`{"foo": {"S": "string", "I": 1}}`), &in.StructMap); err != nil { + panic(err) + } + } + if in.PtrStructMap == nil { + if err := json.Unmarshal([]byte(`{"foo": {"S": "string", "I": 1}}`), &in.PtrStructMap); err != nil { + panic(err) + } + } + if in.AliasPtr == nil { + var ptrVar1 string = "banana" + in.AliasPtr = &ptrVar1 + } +} + +func SetObjectDefaults_DefaultedWithFunction(in *DefaultedWithFunction) { + SetDefaults_DefaultedWithFunction(in) + if in.S1 == "" { + in.S1 = "default_marker" + } + if in.S2 == "" { + in.S2 = "default_marker" + } +} + +func SetObjectDefaults_DefaultedWithReference(in *DefaultedWithReference) { + if in.AliasConvertDefaultPointer == nil { + ptrVar1 := DefaultedValueItem(SomeValue) + in.AliasConvertDefaultPointer = &ptrVar1 + } + if in.PointerAliasDefault == nil { + var ptrVar1 string = "apple" + in.PointerAliasDefault = &ptrVar1 + } + if in.AliasPointerInside == nil { + ptrVar1 := string(SomeDefault) + in.AliasPointerInside = &ptrVar1 + } + if in.AliasOverride == nil { + ptrVar1 := string(SomeDefault) + in.AliasOverride = &ptrVar1 + } + if in.AliasPointerDefault == nil { + ptrVar1 := DefaultedValueItem(SomeValue) + in.AliasPointerDefault = &ptrVar1 + } + if in.AliasNonPointer == "" { + in.AliasNonPointer = ValueItem(SomeValue) + } + if in.AliasPointer == nil { + ptrVar1 := ValueItem(SomeValue) + in.AliasPointer = &ptrVar1 + } + if in.SymbolReference == "" { + in.SymbolReference = string(SomeDefault) + } + if in.SameNamePackageSymbolReference1 == "" { + in.SameNamePackageSymbolReference1 = string(external.AConstant) + } + if in.SameNamePackageSymbolReference2 == "" { + in.SameNamePackageSymbolReference2 = string(externalexternal.AnotherConstant) + } + if in.PointerConversion == nil { + ptrVar9 := string(SomeValue) + ptrVar8 := &ptrVar9 + ptrVar7 := (*B1)(&ptrVar8) + ptrVar6 := (*B2)(&ptrVar7) + ptrVar5 := &ptrVar6 + ptrVar4 := &ptrVar5 + ptrVar3 := &ptrVar4 + ptrVar2 := (*B3)(&ptrVar3) + ptrVar1 := &ptrVar2 + in.PointerConversion = (*B4)(&ptrVar1) + } + if in.PointerConversionValue == nil { + ptrVar8 := string(SomeValue) + ptrVar7 := &ptrVar8 + ptrVar6 := (*B1)(&ptrVar7) + ptrVar5 := (*B2)(&ptrVar6) + ptrVar4 := &ptrVar5 + ptrVar3 := &ptrVar4 + ptrVar2 := &ptrVar3 + ptrVar1 := (*B3)(&ptrVar2) + in.PointerConversionValue = &ptrVar1 + } + if in.FullyQualifiedLocalSymbol == "" { + in.FullyQualifiedLocalSymbol = string(SomeValue) + } + if in.ImportFromAliasCast == nil { + ptrVar1 := external2.String(SomeValue) + in.ImportFromAliasCast = &ptrVar1 + } +} diff --git a/code-generator/cmd/defaulter-gen/output_tests/pointer/defaults.go b/code-generator/cmd/defaulter-gen/output_tests/pointer/defaults.go new file mode 100644 index 000000000..e656f5037 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/pointer/defaults.go @@ -0,0 +1,33 @@ +/* +Copyright 2018 The Kubernetes 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 pointer + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +//nolint:unused +func addDefaultingFuncs(scheme *runtime.Scheme) error { + return RegisterDefaults(scheme) +} + +func SetDefaults_Tpointer(obj *Tpointer) { + if obj.BoolField == nil { + obj.BoolField = new(bool) + *obj.BoolField = true + } +} diff --git a/code-generator/cmd/defaulter-gen/output_tests/pointer/doc.go b/code-generator/cmd/defaulter-gen/output_tests/pointer/doc.go new file mode 100644 index 000000000..0585a1b70 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/pointer/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 The Kubernetes 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. +*/ + +// +k8s:defaulter-gen=TypeMeta + +// This is a test package. +package pointer // import "k8s.io/code-generator/cmd/defaulter-gen/output_tests/pointer" diff --git a/code-generator/cmd/defaulter-gen/output_tests/pointer/fake_deepcopy_conversion.go b/code-generator/cmd/defaulter-gen/output_tests/pointer/fake_deepcopy_conversion.go new file mode 100644 index 000000000..c74e764bb --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/pointer/fake_deepcopy_conversion.go @@ -0,0 +1,82 @@ +/* +Copyright 2023 The Kubernetes 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 pointer + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Tpointer) DeepCopyInto(out *Tpointer) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.BoolField != nil { + in, out := &in.BoolField, &out.BoolField + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Tpointer. +func (in *Tpointer) DeepCopy() *Tpointer { + if in == nil { + return nil + } + out := new(Tpointer) + in.DeepCopyInto(out) + return out +} + +func (in *Tpointer) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Ttest) DeepCopyInto(out *Ttest) { + *out = *in + out.TypeMeta = in.TypeMeta + in.NTP.DeepCopyInto(&out.NTP) + if in.Tp != nil { + in, out := &in.Tp, &out.Tp + *out = new(Tpointer) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest. +func (in *Ttest) DeepCopy() *Ttest { + if in == nil { + return nil + } + out := new(Ttest) + in.DeepCopyInto(out) + return out +} + +func (in *Ttest) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +func (in *Tpointer) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } +func (in *Ttest) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } diff --git a/code-generator/cmd/defaulter-gen/output_tests/pointer/type.go b/code-generator/cmd/defaulter-gen/output_tests/pointer/type.go new file mode 100644 index 000000000..5398a42aa --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/pointer/type.go @@ -0,0 +1,33 @@ +/* +Copyright 2018 The Kubernetes 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 pointer + +import ( + "k8s.io/code-generator/cmd/defaulter-gen/output_tests/empty" +) + +type Tpointer struct { + empty.TypeMeta + BoolField *bool +} + +// Only test +type Ttest struct { + empty.TypeMeta + NTP Tpointer + Tp *Tpointer +} diff --git a/code-generator/cmd/defaulter-gen/output_tests/pointer/zz_generated.defaults.go b/code-generator/cmd/defaulter-gen/output_tests/pointer/zz_generated.defaults.go new file mode 100644 index 000000000..8bee913db --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/pointer/zz_generated.defaults.go @@ -0,0 +1,46 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package pointer + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + scheme.AddTypeDefaultingFunc(&Tpointer{}, func(obj interface{}) { SetObjectDefaults_Tpointer(obj.(*Tpointer)) }) + scheme.AddTypeDefaultingFunc(&Ttest{}, func(obj interface{}) { SetObjectDefaults_Ttest(obj.(*Ttest)) }) + return nil +} + +func SetObjectDefaults_Tpointer(in *Tpointer) { + SetDefaults_Tpointer(in) +} + +func SetObjectDefaults_Ttest(in *Ttest) { + SetObjectDefaults_Tpointer(&in.NTP) + if in.Tp != nil { + SetObjectDefaults_Tpointer(in.Tp) + } +} diff --git a/code-generator/cmd/defaulter-gen/output_tests/slices/defaults.go b/code-generator/cmd/defaulter-gen/output_tests/slices/defaults.go new file mode 100644 index 000000000..21a2ee25c --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/slices/defaults.go @@ -0,0 +1,33 @@ +/* +Copyright 2018 The Kubernetes 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 slices + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +//nolint:unused +func addDefaultingFuncs(scheme *runtime.Scheme) error { + return RegisterDefaults(scheme) +} + +func SetDefaults_Ttest(obj *Ttest) { + if obj.BoolField == nil { + obj.BoolField = new(bool) + *obj.BoolField = true + } +} diff --git a/code-generator/cmd/defaulter-gen/output_tests/slices/doc.go b/code-generator/cmd/defaulter-gen/output_tests/slices/doc.go new file mode 100644 index 000000000..c34190502 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/slices/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 The Kubernetes 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. +*/ + +// +k8s:defaulter-gen=TypeMeta + +// This is a test package. +package slices // import "k8s.io/code-generator/cmd/defaulter-gen/output_tests/slices" diff --git a/code-generator/cmd/defaulter-gen/output_tests/slices/fake_deepcopy_conversion.go b/code-generator/cmd/defaulter-gen/output_tests/slices/fake_deepcopy_conversion.go new file mode 100644 index 000000000..ab07e3da7 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/slices/fake_deepcopy_conversion.go @@ -0,0 +1,118 @@ +/* +Copyright 2023 The Kubernetes 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 slices + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Ttest) DeepCopyInto(out *Ttest) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.BoolField != nil { + in, out := &in.BoolField, &out.BoolField + *out = new(bool) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Ttest. +func (in *Ttest) DeepCopy() *Ttest { + if in == nil { + return nil + } + out := new(Ttest) + in.DeepCopyInto(out) + return out +} + +func (in *Ttest) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TtestList) DeepCopyInto(out *TtestList) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Ttest, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TtestList. +func (in *TtestList) DeepCopy() *TtestList { + if in == nil { + return nil + } + out := new(TtestList) + in.DeepCopyInto(out) + return out +} + +func (in *TtestList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TtestPointerList) DeepCopyInto(out *TtestPointerList) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]*Ttest, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Ttest) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TtestPointerList. +func (in *TtestPointerList) DeepCopy() *TtestPointerList { + if in == nil { + return nil + } + out := new(TtestPointerList) + in.DeepCopyInto(out) + return out +} + +func (in *TtestPointerList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +func (in *Ttest) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } +func (in *TtestList) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } +func (in *TtestPointerList) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } diff --git a/code-generator/cmd/defaulter-gen/output_tests/slices/type.go b/code-generator/cmd/defaulter-gen/output_tests/slices/type.go new file mode 100644 index 000000000..0b0a79f4f --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/slices/type.go @@ -0,0 +1,37 @@ +/* +Copyright 2018 The Kubernetes 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 slices + +import ( + "k8s.io/code-generator/cmd/defaulter-gen/output_tests/empty" +) + +// Only test +type Ttest struct { + empty.TypeMeta + BoolField *bool +} + +type TtestList struct { + empty.TypeMeta + Items []Ttest +} + +type TtestPointerList struct { + empty.TypeMeta + Items []*Ttest +} diff --git a/code-generator/cmd/defaulter-gen/output_tests/slices/zz_generated.defaults.go b/code-generator/cmd/defaulter-gen/output_tests/slices/zz_generated.defaults.go new file mode 100644 index 000000000..a7d6e2678 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/slices/zz_generated.defaults.go @@ -0,0 +1,56 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package slices + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + scheme.AddTypeDefaultingFunc(&Ttest{}, func(obj interface{}) { SetObjectDefaults_Ttest(obj.(*Ttest)) }) + scheme.AddTypeDefaultingFunc(&TtestList{}, func(obj interface{}) { SetObjectDefaults_TtestList(obj.(*TtestList)) }) + scheme.AddTypeDefaultingFunc(&TtestPointerList{}, func(obj interface{}) { SetObjectDefaults_TtestPointerList(obj.(*TtestPointerList)) }) + return nil +} + +func SetObjectDefaults_Ttest(in *Ttest) { + SetDefaults_Ttest(in) +} + +func SetObjectDefaults_TtestList(in *TtestList) { + for i := range in.Items { + a := &in.Items[i] + SetObjectDefaults_Ttest(a) + } +} + +func SetObjectDefaults_TtestPointerList(in *TtestPointerList) { + for i := range in.Items { + a := in.Items[i] + if a != nil { + SetObjectDefaults_Ttest(a) + } + } +} diff --git a/code-generator/cmd/defaulter-gen/output_tests/wholepkg/defaults.go b/code-generator/cmd/defaulter-gen/output_tests/wholepkg/defaults.go new file mode 100644 index 000000000..bcfdde1a3 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/wholepkg/defaults.go @@ -0,0 +1,33 @@ +/* +Copyright 2018 The Kubernetes 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 wholepkg + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +//nolint:unused +func addDefaultingFuncs(scheme *runtime.Scheme) error { + return RegisterDefaults(scheme) +} + +func SetDefaults_StructPrimitives(obj *StructPrimitives) { + if obj.BoolField == nil { + obj.BoolField = new(bool) + *obj.BoolField = true + } +} diff --git a/code-generator/cmd/defaulter-gen/output_tests/wholepkg/doc.go b/code-generator/cmd/defaulter-gen/output_tests/wholepkg/doc.go new file mode 100644 index 000000000..d9a629997 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/wholepkg/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2018 The Kubernetes 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. +*/ + +// +k8s:defaulter-gen=TypeMeta + +// This is a test package. +package wholepkg // import "k8s.io/code-generator/cmd/defaulter-gen/output_tests/wholepkg" diff --git a/code-generator/cmd/defaulter-gen/output_tests/wholepkg/fake_deepcopy_conversion.go b/code-generator/cmd/defaulter-gen/output_tests/wholepkg/fake_deepcopy_conversion.go new file mode 100644 index 000000000..e896bf726 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/wholepkg/fake_deepcopy_conversion.go @@ -0,0 +1,315 @@ +/* +Copyright 2023 The Kubernetes 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 wholepkg + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructEverything) DeepCopyInto(out *StructEverything) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.BoolPtrField != nil { + in, out := &in.BoolPtrField, &out.BoolPtrField + *out = new(bool) + **out = **in + } + if in.IntPtrField != nil { + in, out := &in.IntPtrField, &out.IntPtrField + *out = new(int) + **out = **in + } + if in.StringPtrField != nil { + in, out := &in.StringPtrField, &out.StringPtrField + *out = new(string) + **out = **in + } + if in.FloatPtrField != nil { + in, out := &in.FloatPtrField, &out.FloatPtrField + *out = new(float64) + **out = **in + } + in.PointerStructField.DeepCopyInto(&out.PointerStructField) + if in.SliceBoolField != nil { + in, out := &in.SliceBoolField, &out.SliceBoolField + *out = make([]bool, len(*in)) + copy(*out, *in) + } + if in.SliceByteField != nil { + in, out := &in.SliceByteField, &out.SliceByteField + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.SliceIntField != nil { + in, out := &in.SliceIntField, &out.SliceIntField + *out = make([]int, len(*in)) + copy(*out, *in) + } + if in.SliceStringField != nil { + in, out := &in.SliceStringField, &out.SliceStringField + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.SliceFloatField != nil { + in, out := &in.SliceFloatField, &out.SliceFloatField + *out = make([]float64, len(*in)) + copy(*out, *in) + } + in.SlicesStructField.DeepCopyInto(&out.SlicesStructField) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructEverything. +func (in *StructEverything) DeepCopy() *StructEverything { + if in == nil { + return nil + } + out := new(StructEverything) + in.DeepCopyInto(out) + return out +} + +func (in *StructEverything) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructPointer) DeepCopyInto(out *StructPointer) { + *out = *in + out.TypeMeta = in.TypeMeta + in.PointerStructPrimitivesField.DeepCopyInto(&out.PointerStructPrimitivesField) + if in.PointerPointerStructPrimitivesField != nil { + in, out := &in.PointerPointerStructPrimitivesField, &out.PointerPointerStructPrimitivesField + *out = new(StructPrimitives) + (*in).DeepCopyInto(*out) + } + in.PointerStructPrimitivesAliasField.DeepCopyInto(&out.PointerStructPrimitivesAliasField) + in.PointerPointerStructPrimitivesAliasField.DeepCopyInto(&out.PointerPointerStructPrimitivesAliasField) + in.PointerStructStructPrimitives.DeepCopyInto(&out.PointerStructStructPrimitives) + if in.PointerPointerStructStructPrimitives != nil { + in, out := &in.PointerPointerStructStructPrimitives, &out.PointerPointerStructStructPrimitives + *out = new(StructStructPrimitives) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructPointer. +func (in *StructPointer) DeepCopy() *StructPointer { + if in == nil { + return nil + } + out := new(StructPointer) + in.DeepCopyInto(out) + return out +} + +func (in *StructPointer) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructPrimitives) DeepCopyInto(out *StructPrimitives) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.BoolField != nil { + in, out := &in.BoolField, &out.BoolField + *out = new(bool) + **out = **in + } + if in.IntField != nil { + in, out := &in.IntField, &out.IntField + *out = new(int) + **out = **in + } + if in.StringField != nil { + in, out := &in.StringField, &out.StringField + *out = new(string) + **out = **in + } + if in.FloatField != nil { + in, out := &in.FloatField, &out.FloatField + *out = new(float64) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructPrimitives. +func (in *StructPrimitives) DeepCopy() *StructPrimitives { + if in == nil { + return nil + } + out := new(StructPrimitives) + in.DeepCopyInto(out) + return out +} + +func (in *StructPrimitives) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructPrimitivesAlias) DeepCopyInto(out *StructPrimitivesAlias) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.BoolField != nil { + in, out := &in.BoolField, &out.BoolField + *out = new(bool) + **out = **in + } + if in.IntField != nil { + in, out := &in.IntField, &out.IntField + *out = new(int) + **out = **in + } + if in.StringField != nil { + in, out := &in.StringField, &out.StringField + *out = new(string) + **out = **in + } + if in.FloatField != nil { + in, out := &in.FloatField, &out.FloatField + *out = new(float64) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructPrimitivesAlias. +func (in *StructPrimitivesAlias) DeepCopy() *StructPrimitivesAlias { + if in == nil { + return nil + } + out := new(StructPrimitivesAlias) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructSlices) DeepCopyInto(out *StructSlices) { + *out = *in + out.TypeMeta = in.TypeMeta + if in.SliceStructPrimitivesField != nil { + in, out := &in.SliceStructPrimitivesField, &out.SliceStructPrimitivesField + *out = make([]StructPrimitives, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.SlicePointerStructPrimitivesField != nil { + in, out := &in.SlicePointerStructPrimitivesField, &out.SlicePointerStructPrimitivesField + *out = make([]*StructPrimitives, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(StructPrimitives) + (*in).DeepCopyInto(*out) + } + } + } + if in.SliceStructPrimitivesAliasField != nil { + in, out := &in.SliceStructPrimitivesAliasField, &out.SliceStructPrimitivesAliasField + *out = make([]StructPrimitivesAlias, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.SlicePointerStructPrimitivesAliasField != nil { + in, out := &in.SlicePointerStructPrimitivesAliasField, &out.SlicePointerStructPrimitivesAliasField + *out = make([]*StructPrimitivesAlias, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(StructPrimitivesAlias) + (*in).DeepCopyInto(*out) + } + } + } + if in.SliceStructStructPrimitives != nil { + in, out := &in.SliceStructStructPrimitives, &out.SliceStructStructPrimitives + *out = make([]StructStructPrimitives, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.SlicePointerStructStructPrimitives != nil { + in, out := &in.SlicePointerStructStructPrimitives, &out.SlicePointerStructStructPrimitives + *out = make([]*StructStructPrimitives, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(StructStructPrimitives) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructSlices. +func (in *StructSlices) DeepCopy() *StructSlices { + if in == nil { + return nil + } + out := new(StructSlices) + in.DeepCopyInto(out) + return out +} + +func (in *StructSlices) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StructStructPrimitives) DeepCopyInto(out *StructStructPrimitives) { + *out = *in + out.TypeMeta = in.TypeMeta + in.StructField.DeepCopyInto(&out.StructField) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StructStructPrimitives. +func (in *StructStructPrimitives) DeepCopy() *StructStructPrimitives { + if in == nil { + return nil + } + out := new(StructStructPrimitives) + in.DeepCopyInto(out) + return out +} + +func (in *StructStructPrimitives) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +func (in *StructEverything) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } +func (in *StructPointer) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } +func (in *StructPrimitives) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } +func (in *StructSlices) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } +func (in *StructStructPrimitives) GetObjectKind() schema.ObjectKind { return schema.EmptyObjectKind } diff --git a/code-generator/cmd/defaulter-gen/output_tests/wholepkg/type.go b/code-generator/cmd/defaulter-gen/output_tests/wholepkg/type.go new file mode 100644 index 000000000..80a83b746 --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/wholepkg/type.go @@ -0,0 +1,74 @@ +/* +Copyright 2018 The Kubernetes 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 wholepkg + +import ( + "k8s.io/code-generator/cmd/defaulter-gen/output_tests/empty" +) + +// Only primitives +type StructPrimitives struct { + empty.TypeMeta + BoolField *bool + IntField *int + StringField *string + FloatField *float64 +} +type StructPrimitivesAlias StructPrimitives + +type StructStructPrimitives struct { + empty.TypeMeta + StructField StructPrimitives +} + +// Pointer +type StructPointer struct { + empty.TypeMeta + PointerStructPrimitivesField StructPrimitives + PointerPointerStructPrimitivesField *StructPrimitives + PointerStructPrimitivesAliasField StructPrimitivesAlias + PointerPointerStructPrimitivesAliasField StructPrimitivesAlias + PointerStructStructPrimitives StructStructPrimitives + PointerPointerStructStructPrimitives *StructStructPrimitives +} + +// Slices +type StructSlices struct { + empty.TypeMeta + SliceStructPrimitivesField []StructPrimitives + SlicePointerStructPrimitivesField []*StructPrimitives + SliceStructPrimitivesAliasField []StructPrimitivesAlias + SlicePointerStructPrimitivesAliasField []*StructPrimitivesAlias + SliceStructStructPrimitives []StructStructPrimitives + SlicePointerStructStructPrimitives []*StructStructPrimitives +} + +// Everything +type StructEverything struct { + empty.TypeMeta + BoolPtrField *bool + IntPtrField *int + StringPtrField *string + FloatPtrField *float64 + PointerStructField StructPointer + SliceBoolField []bool + SliceByteField []byte + SliceIntField []int + SliceStringField []string + SliceFloatField []float64 + SlicesStructField StructSlices +} diff --git a/code-generator/cmd/defaulter-gen/output_tests/wholepkg/zz_generated.defaults.go b/code-generator/cmd/defaulter-gen/output_tests/wholepkg/zz_generated.defaults.go new file mode 100644 index 000000000..26c7991bd --- /dev/null +++ b/code-generator/cmd/defaulter-gen/output_tests/wholepkg/zz_generated.defaults.go @@ -0,0 +1,85 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package wholepkg + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + scheme.AddTypeDefaultingFunc(&StructEverything{}, func(obj interface{}) { SetObjectDefaults_StructEverything(obj.(*StructEverything)) }) + scheme.AddTypeDefaultingFunc(&StructPointer{}, func(obj interface{}) { SetObjectDefaults_StructPointer(obj.(*StructPointer)) }) + scheme.AddTypeDefaultingFunc(&StructPrimitives{}, func(obj interface{}) { SetObjectDefaults_StructPrimitives(obj.(*StructPrimitives)) }) + scheme.AddTypeDefaultingFunc(&StructSlices{}, func(obj interface{}) { SetObjectDefaults_StructSlices(obj.(*StructSlices)) }) + scheme.AddTypeDefaultingFunc(&StructStructPrimitives{}, func(obj interface{}) { SetObjectDefaults_StructStructPrimitives(obj.(*StructStructPrimitives)) }) + return nil +} + +func SetObjectDefaults_StructEverything(in *StructEverything) { + SetObjectDefaults_StructPointer(&in.PointerStructField) + SetObjectDefaults_StructSlices(&in.SlicesStructField) +} + +func SetObjectDefaults_StructPointer(in *StructPointer) { + SetObjectDefaults_StructPrimitives(&in.PointerStructPrimitivesField) + if in.PointerPointerStructPrimitivesField != nil { + SetObjectDefaults_StructPrimitives(in.PointerPointerStructPrimitivesField) + } + SetObjectDefaults_StructStructPrimitives(&in.PointerStructStructPrimitives) + if in.PointerPointerStructStructPrimitives != nil { + SetObjectDefaults_StructStructPrimitives(in.PointerPointerStructStructPrimitives) + } +} + +func SetObjectDefaults_StructPrimitives(in *StructPrimitives) { + SetDefaults_StructPrimitives(in) +} + +func SetObjectDefaults_StructSlices(in *StructSlices) { + for i := range in.SliceStructPrimitivesField { + a := &in.SliceStructPrimitivesField[i] + SetObjectDefaults_StructPrimitives(a) + } + for i := range in.SlicePointerStructPrimitivesField { + a := in.SlicePointerStructPrimitivesField[i] + if a != nil { + SetObjectDefaults_StructPrimitives(a) + } + } + for i := range in.SliceStructStructPrimitives { + a := &in.SliceStructStructPrimitives[i] + SetObjectDefaults_StructStructPrimitives(a) + } + for i := range in.SlicePointerStructStructPrimitives { + a := in.SlicePointerStructStructPrimitives[i] + if a != nil { + SetObjectDefaults_StructStructPrimitives(a) + } + } +} + +func SetObjectDefaults_StructStructPrimitives(in *StructStructPrimitives) { + SetObjectDefaults_StructPrimitives(&in.StructField) +} diff --git a/code-generator/cmd/go-to-protobuf/.gitignore b/code-generator/cmd/go-to-protobuf/.gitignore new file mode 100644 index 000000000..0e9aa466b --- /dev/null +++ b/code-generator/cmd/go-to-protobuf/.gitignore @@ -0,0 +1 @@ +go-to-protobuf diff --git a/code-generator/cmd/go-to-protobuf/OWNERS b/code-generator/cmd/go-to-protobuf/OWNERS new file mode 100644 index 000000000..af7e2ec4c --- /dev/null +++ b/code-generator/cmd/go-to-protobuf/OWNERS @@ -0,0 +1,6 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +approvers: + - smarterclayton +reviewers: + - smarterclayton diff --git a/code-generator/cmd/go-to-protobuf/main.go b/code-generator/cmd/go-to-protobuf/main.go new file mode 100644 index 000000000..009973389 --- /dev/null +++ b/code-generator/cmd/go-to-protobuf/main.go @@ -0,0 +1,41 @@ +/* +Copyright 2015 The Kubernetes 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. +*/ + +// go-to-protobuf generates a Protobuf IDL from a Go struct, respecting any +// existing IDL tags on the Go struct. +package main + +import ( + goflag "flag" + + flag "github.com/spf13/pflag" + "k8s.io/code-generator/cmd/go-to-protobuf/protobuf" + "k8s.io/klog/v2" +) + +var g = protobuf.New() + +func init() { + klog.InitFlags(nil) + g.BindFlags(flag.CommandLine) + goflag.Set("logtostderr", "true") + flag.CommandLine.AddGoFlagSet(goflag.CommandLine) +} + +func main() { + flag.Parse() + protobuf.Run(g) +} diff --git a/code-generator/cmd/go-to-protobuf/protobuf/cmd.go b/code-generator/cmd/go-to-protobuf/protobuf/cmd.go new file mode 100644 index 000000000..ca21c76c3 --- /dev/null +++ b/code-generator/cmd/go-to-protobuf/protobuf/cmd.go @@ -0,0 +1,456 @@ +/* +Copyright 2015 The Kubernetes 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. +*/ + +// go-to-protobuf generates a Protobuf IDL from a Go struct, respecting any +// existing IDL tags on the Go struct. +package protobuf + +import ( + "bytes" + "fmt" + "log" + "os/exec" + "path/filepath" + "sort" + "strings" + + flag "github.com/spf13/pflag" + + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/parser" + "k8s.io/gengo/v2/types" +) + +type Generator struct { + GoHeaderFile string + APIMachineryPackages string + Packages string + OutputDir string + ProtoImport []string + Conditional string + Clean bool + OnlyIDL bool + KeepGogoproto bool + SkipGeneratedRewrite bool + DropEmbeddedFields string +} + +func New() *Generator { + defaultSourceTree := "." + return &Generator{ + OutputDir: defaultSourceTree, + APIMachineryPackages: strings.Join([]string{ + `+k8s.io/apimachinery/pkg/util/intstr`, + `+k8s.io/apimachinery/pkg/api/resource`, + `+k8s.io/apimachinery/pkg/runtime/schema`, + `+k8s.io/apimachinery/pkg/runtime`, + `k8s.io/apimachinery/pkg/apis/meta/v1`, + `k8s.io/apimachinery/pkg/apis/meta/v1beta1`, + `k8s.io/apimachinery/pkg/apis/testapigroup/v1`, + }, ","), + Packages: "", + DropEmbeddedFields: "k8s.io/apimachinery/pkg/apis/meta/v1.TypeMeta", + } +} + +func (g *Generator) BindFlags(flag *flag.FlagSet) { + flag.StringVarP(&g.GoHeaderFile, "go-header-file", "h", "", "File containing boilerplate header text. The string YEAR will be replaced with the current 4-digit year.") + flag.StringVarP(&g.Packages, "packages", "p", g.Packages, "comma-separated list of directories to get input types from. Directories prefixed with '-' are not generated, directories prefixed with '+' only create types with explicit IDL instructions.") + flag.StringVar(&g.APIMachineryPackages, "apimachinery-packages", g.APIMachineryPackages, "comma-separated list of directories to get apimachinery input types from which are needed by any API. Directories prefixed with '-' are not generated, directories prefixed with '+' only create types with explicit IDL instructions.") + flag.StringVar(&g.OutputDir, "output-dir", g.OutputDir, "The base directory under which to generate results.") + flag.StringSliceVar(&g.ProtoImport, "proto-import", g.ProtoImport, "A search path for imported protobufs (may be repeated).") + flag.StringVar(&g.Conditional, "conditional", g.Conditional, "An optional Golang build tag condition to add to the generated Go code") + flag.BoolVar(&g.Clean, "clean", g.Clean, "If true, remove all generated files for the specified Packages.") + flag.BoolVar(&g.OnlyIDL, "only-idl", g.OnlyIDL, "If true, only generate the IDL for each package.") + flag.BoolVar(&g.KeepGogoproto, "keep-gogoproto", g.KeepGogoproto, "If true, the generated IDL will contain gogoprotobuf extensions which are normally removed") + flag.BoolVar(&g.SkipGeneratedRewrite, "skip-generated-rewrite", g.SkipGeneratedRewrite, "If true, skip fixing up the generated.pb.go file (debugging only).") + flag.StringVar(&g.DropEmbeddedFields, "drop-embedded-fields", g.DropEmbeddedFields, "Comma-delimited list of embedded Go types to omit from generated protobufs") +} + +// This roughly models gengo/v2.Execute. +func Run(g *Generator) { + // Roughly models gengo/v2.newBuilder. + + p := parser.NewWithOptions(parser.Options{BuildTags: []string{"proto"}}) + + var allInputs []string + if len(g.APIMachineryPackages) != 0 { + allInputs = append(allInputs, strings.Split(g.APIMachineryPackages, ",")...) + } + if len(g.Packages) != 0 { + allInputs = append(allInputs, strings.Split(g.Packages, ",")...) + } + if len(allInputs) == 0 { + log.Fatalf("Both apimachinery-packages and packages are empty. At least one package must be specified.") + } + + // Build up a list of packages to load from all the inputs. Track the + // special modifiers for each. NOTE: This does not support pkg/... syntax. + type modifier struct { + allTypes bool + output bool + name string + } + inputModifiers := map[string]modifier{} + packages := make([]string, 0, len(allInputs)) + + for _, d := range allInputs { + modifier := modifier{allTypes: true, output: true} + + switch { + case strings.HasPrefix(d, "+"): + d = d[1:] + modifier.allTypes = false + case strings.HasPrefix(d, "-"): + d = d[1:] + modifier.output = false + } + name := protoSafePackage(d) + parts := strings.SplitN(d, "=", 2) + if len(parts) > 1 { + d = parts[0] + name = parts[1] + } + modifier.name = name + + packages = append(packages, d) + inputModifiers[d] = modifier + } + + // Load all the packages at once. + if err := p.LoadPackages(packages...); err != nil { + log.Fatalf("Unable to load packages: %v", err) + } + + c, err := generator.NewContext( + p, + namer.NameSystems{ + "public": namer.NewPublicNamer(3), + }, + "public", + ) + if err != nil { + log.Fatalf("Failed making a context: %v", err) + } + + c.FileTypes["protoidl"] = NewProtoFile() + + // Roughly models gengo/v2.Execute calling the + // tool-provided Targets() callback. + + boilerplate, err := gengo.GoBoilerplate(g.GoHeaderFile, "", "") + if err != nil { + log.Fatalf("Failed loading boilerplate (consider using the go-header-file flag): %v", err) + } + + omitTypes := map[types.Name]struct{}{} + for _, t := range strings.Split(g.DropEmbeddedFields, ",") { + name := types.Name{} + if i := strings.LastIndex(t, "."); i != -1 { + name.Package, name.Name = t[:i], t[i+1:] + } else { + name.Name = t + } + if len(name.Name) == 0 { + log.Fatalf("--drop-embedded-types requires names in the form of [GOPACKAGE.]TYPENAME: %v", t) + } + omitTypes[name] = struct{}{} + } + + protobufNames := NewProtobufNamer() + outputPackages := []generator.Target{} + nonOutputPackages := map[string]struct{}{} + + for _, input := range c.Inputs { + mod, found := inputModifiers[input] + if !found { + log.Fatalf("BUG: can't find input modifiers for %q", input) + } + pkg := c.Universe[input] + protopkg := newProtobufPackage(pkg.Path, pkg.Dir, mod.name, mod.allTypes, omitTypes) + header := append([]byte{}, boilerplate...) + header = append(header, protopkg.HeaderComment...) + protopkg.HeaderComment = header + protobufNames.Add(protopkg) + if mod.output { + outputPackages = append(outputPackages, protopkg) + } else { + nonOutputPackages[mod.name] = struct{}{} + } + } + c.Namers["proto"] = protobufNames + + for _, p := range outputPackages { + if err := p.(*protobufPackage).Clean(); err != nil { + log.Fatalf("Unable to clean package %s: %v", p.Name(), err) + } + } + + if g.Clean { + return + } + + // order package by imports, importees first + deps := deps(c, protobufNames.packages) + order, err := importOrder(deps) + if err != nil { + log.Fatalf("Failed to order packages by imports: %v", err) + } + topologicalPos := map[string]int{} + for i, p := range order { + topologicalPos[p] = i + } + sort.Sort(positionOrder{topologicalPos, protobufNames.packages}) + + var localOutputPackages []generator.Target + for _, p := range protobufNames.packages { + if _, ok := nonOutputPackages[p.Name()]; ok { + // if we're not outputting the package, don't include it in either package list + continue + } + localOutputPackages = append(localOutputPackages, p) + } + + if err := protobufNames.AssignTypesToPackages(c); err != nil { + log.Fatalf("Failed to identify Common types: %v", err) + } + + if err := c.ExecuteTargets(localOutputPackages); err != nil { + log.Fatalf("Failed executing local generator: %v", err) + } + + if g.OnlyIDL { + return + } + + if _, err := exec.LookPath("protoc"); err != nil { + log.Fatalf("Unable to find 'protoc': %v", err) + } + + searchArgs := []string{"-I", ".", "-I", g.OutputDir} + if len(g.ProtoImport) != 0 { + for _, s := range g.ProtoImport { + searchArgs = append(searchArgs, "-I", s) + } + } + // Despite docs saying that `--gogo_out=paths=source_relative:.` will + // output the .pb.go file to the same directory as the .proto file, it + // doesn't. Given example.com/foo/bar.proto (found in one of the -I paths + // above), the output becomes + // $output_base/example.com/foo/example.com/foo/bar.pb.go - basically + // useless. Users should set the output-dir to a single dir under which + // all the packages in question live (e.g. staging/src in kubernetes). + // Alternately, we could generate into a temp path and then move the + // resulting file back to the input dir, but that seems brittle in other + // ways. + args := searchArgs + args = append(args, fmt.Sprintf("--gogo_out=%s", g.OutputDir)) + + buf := &bytes.Buffer{} + if len(g.Conditional) > 0 { + fmt.Fprintf(buf, "// +build %s\n\n", g.Conditional) + } + buf.Write(boilerplate) + + for _, outputPackage := range outputPackages { + p := outputPackage.(*protobufPackage) + + path := filepath.Join(g.OutputDir, p.ImportPath()) + outputPath := filepath.Join(g.OutputDir, p.OutputPath()) + + // generate the gogoprotobuf protoc + cmd := exec.Command("protoc", append(args, path)...) + out, err := cmd.CombinedOutput() + if err != nil { + log.Println(strings.Join(cmd.Args, " ")) + log.Println(string(out)) + log.Fatalf("Unable to run protoc on %s: %v", p.Name(), err) + } + + if g.SkipGeneratedRewrite { + continue + } + + // alter the generated protobuf file to remove the generated types (but leave the serializers) and rewrite the + // package statement to match the desired package name + if err := RewriteGeneratedGogoProtobufFile(outputPath, p.ExtractGeneratedType, p.OptionalTypeName, buf.Bytes()); err != nil { + log.Fatalf("Unable to rewrite generated %s: %v", outputPath, err) + } + + // sort imports + cmd = exec.Command("goimports", "-w", outputPath) + out, err = cmd.CombinedOutput() + if len(out) > 0 { + log.Print(string(out)) + } + if err != nil { + log.Println(strings.Join(cmd.Args, " ")) + log.Fatalf("Unable to rewrite imports for %s: %v", p.Name(), err) + } + + // format and simplify the generated file + cmd = exec.Command("gofmt", "-s", "-w", outputPath) + out, err = cmd.CombinedOutput() + if len(out) > 0 { + log.Print(string(out)) + } + if err != nil { + log.Println(strings.Join(cmd.Args, " ")) + log.Fatalf("Unable to apply gofmt for %s: %v", p.Name(), err) + } + } + + if g.SkipGeneratedRewrite { + return + } + + if !g.KeepGogoproto { + // generate, but do so without gogoprotobuf extensions + for _, outputPackage := range outputPackages { + p := outputPackage.(*protobufPackage) + p.OmitGogo = true + } + if err := c.ExecuteTargets(localOutputPackages); err != nil { + log.Fatalf("Failed executing local generator: %v", err) + } + } + + for _, outputPackage := range outputPackages { + p := outputPackage.(*protobufPackage) + + if len(p.StructTags) == 0 { + continue + } + + pattern := filepath.Join(g.OutputDir, p.Path(), "*.go") + files, err := filepath.Glob(pattern) + if err != nil { + log.Fatalf("Can't glob pattern %q: %v", pattern, err) + } + + for _, s := range files { + if strings.HasSuffix(s, "_test.go") { + continue + } + if err := RewriteTypesWithProtobufStructTags(s, p.StructTags); err != nil { + log.Fatalf("Unable to rewrite with struct tags %s: %v", s, err) + } + } + } +} + +func deps(c *generator.Context, pkgs []*protobufPackage) map[string][]string { + ret := map[string][]string{} + for _, p := range pkgs { + pkg, ok := c.Universe[p.Path()] + if !ok { + log.Fatalf("Unrecognized package: %s", p.Path()) + } + + for _, d := range pkg.Imports { + ret[p.Path()] = append(ret[p.Path()], d.Path) + } + } + return ret +} + +// given a set of pkg->[]deps, return the order that ensures all deps are processed before the things that depend on them +func importOrder(deps map[string][]string) ([]string, error) { + // add all nodes and edges + var remainingNodes = map[string]struct{}{} + var graph = map[edge]struct{}{} + for to, froms := range deps { + remainingNodes[to] = struct{}{} + for _, from := range froms { + remainingNodes[from] = struct{}{} + graph[edge{from: from, to: to}] = struct{}{} + } + } + + // find initial nodes without any dependencies + sorted := findAndRemoveNodesWithoutDependencies(remainingNodes, graph) + for i := 0; i < len(sorted); i++ { + node := sorted[i] + removeEdgesFrom(node, graph) + sorted = append(sorted, findAndRemoveNodesWithoutDependencies(remainingNodes, graph)...) + } + if len(remainingNodes) > 0 { + return nil, fmt.Errorf("cycle: remaining nodes: %#v, remaining edges: %#v", remainingNodes, graph) + } + // for _, n := range sorted { + // fmt.Println("topological order", n) + // } + return sorted, nil +} + +// edge describes a from->to relationship in a graph +type edge struct { + from string + to string +} + +// findAndRemoveNodesWithoutDependencies finds nodes in the given set which are not pointed to by any edges in the graph, +// removes them from the set of nodes, and returns them in sorted order +func findAndRemoveNodesWithoutDependencies(nodes map[string]struct{}, graph map[edge]struct{}) []string { + roots := []string{} + // iterate over all nodes as potential "to" nodes + for node := range nodes { + incoming := false + // iterate over all remaining edges + for edge := range graph { + // if there's any edge to the node we care about, it's not a root + if edge.to == node { + incoming = true + break + } + } + // if there are no incoming edges, remove from the set of remaining nodes and add to our results + if !incoming { + delete(nodes, node) + roots = append(roots, node) + } + } + sort.Strings(roots) + return roots +} + +// removeEdgesFrom removes any edges from the graph where edge.from == node +func removeEdgesFrom(node string, graph map[edge]struct{}) { + for edge := range graph { + if edge.from == node { + delete(graph, edge) + } + } +} + +type positionOrder struct { + pos map[string]int + elements []*protobufPackage +} + +func (o positionOrder) Len() int { + return len(o.elements) +} + +func (o positionOrder) Less(i, j int) bool { + return o.pos[o.elements[i].Path()] < o.pos[o.elements[j].Path()] +} + +func (o positionOrder) Swap(i, j int) { + o.elements[i], o.elements[j] = o.elements[j], o.elements[i] +} diff --git a/code-generator/cmd/go-to-protobuf/protobuf/cmd_test.go b/code-generator/cmd/go-to-protobuf/protobuf/cmd_test.go new file mode 100644 index 000000000..c6b671763 --- /dev/null +++ b/code-generator/cmd/go-to-protobuf/protobuf/cmd_test.go @@ -0,0 +1,65 @@ +/* +Copyright 2020 The Kubernetes 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 protobuf + +import ( + "reflect" + "testing" +) + +func TestImportOrder(t *testing.T) { + testcases := []struct { + Name string + Input map[string][]string + Expect []string + ExpectErr bool + }{ + { + Name: "empty", + Input: nil, + Expect: []string{}, + }, + { + Name: "simple", + Input: map[string][]string{"apps": {"core", "extensions", "meta"}, "extensions": {"core", "meta"}, "core": {"meta"}}, + Expect: []string{"meta", "core", "extensions", "apps"}, + }, + { + Name: "cycle", + Input: map[string][]string{"apps": {"core", "extensions", "meta"}, "extensions": {"core", "meta"}, "core": {"meta", "apps"}}, + ExpectErr: true, + }, + } + + for _, tc := range testcases { + t.Run(tc.Name, func(t *testing.T) { + order, err := importOrder(tc.Input) + if err != nil { + if !tc.ExpectErr { + t.Fatalf("unexpected error: %v", err) + } + return + } + if tc.ExpectErr { + t.Fatalf("expected error, got none") + } + if !reflect.DeepEqual(order, tc.Expect) { + t.Fatalf("expected %v, got %v", tc.Expect, order) + } + }) + } +} diff --git a/code-generator/cmd/go-to-protobuf/protobuf/generator.go b/code-generator/cmd/go-to-protobuf/protobuf/generator.go new file mode 100644 index 000000000..0fc653dda --- /dev/null +++ b/code-generator/cmd/go-to-protobuf/protobuf/generator.go @@ -0,0 +1,777 @@ +/* +Copyright 2015 The Kubernetes 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 protobuf + +import ( + "fmt" + "io" + "log" + "reflect" + "sort" + "strconv" + "strings" + + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + "k8s.io/klog/v2" +) + +// genProtoIDL produces a .proto IDL. +type genProtoIDL struct { + // This base type is close enough to what we need, if we redefine some + // methods. + generator.GoGenerator + localPackage types.Name + localGoPackage types.Name + imports namer.ImportTracker + + generateAll bool + omitGogo bool + omitFieldTypes map[types.Name]struct{} +} + +func (g *genProtoIDL) PackageVars(c *generator.Context) []string { + if g.omitGogo { + return []string{ + fmt.Sprintf("option go_package = %q;", g.localGoPackage.Package), + } + } + return []string{ + "option (gogoproto.marshaler_all) = true;", + "option (gogoproto.stable_marshaler_all) = true;", + "option (gogoproto.sizer_all) = true;", + "option (gogoproto.goproto_stringer_all) = false;", + "option (gogoproto.stringer_all) = true;", + "option (gogoproto.unmarshaler_all) = true;", + "option (gogoproto.goproto_unrecognized_all) = false;", + "option (gogoproto.goproto_enum_prefix_all) = false;", + "option (gogoproto.goproto_getters_all) = false;", + fmt.Sprintf("option go_package = %q;", g.localGoPackage.Package), + } +} + +func (g *genProtoIDL) Filename() string { return g.OutputFilename + ".proto" } + +func (g *genProtoIDL) FileType() string { return "protoidl" } + +func (g *genProtoIDL) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + // The local namer returns the correct protobuf name for a proto type + // in the context of a package + "local": localNamer{g.localPackage}, + } +} + +// Filter ignores types that are identified as not exportable. +func (g *genProtoIDL) Filter(c *generator.Context, t *types.Type) bool { + tagVals := gengo.ExtractCommentTags("+", t.CommentLines)["protobuf"] + if tagVals != nil { + if tagVals[0] == "false" { + // Type specified "false". + return false + } + if tagVals[0] == "true" { + // Type specified "true". + return true + } + klog.Fatalf(`Comment tag "protobuf" must be true or false, found: %q`, tagVals[0]) + } + if !g.generateAll { + // We're not generating everything. + return false + } + seen := map[*types.Type]bool{} + ok := isProtoable(seen, t) + return ok +} + +func isProtoable(seen map[*types.Type]bool, t *types.Type) bool { + if seen[t] { + // be optimistic in the case of type cycles. + return true + } + seen[t] = true + switch t.Kind { + case types.Builtin: + return true + case types.Alias: + return isProtoable(seen, t.Underlying) + case types.Slice, types.Pointer: + return isProtoable(seen, t.Elem) + case types.Map: + return isProtoable(seen, t.Key) && isProtoable(seen, t.Elem) + case types.Struct: + if len(t.Members) == 0 { + return true + } + for _, m := range t.Members { + if isProtoable(seen, m.Type) { + return true + } + } + return false + case types.Func, types.Chan: + return false + case types.DeclarationOf, types.Unknown, types.Unsupported: + return false + case types.Interface: + return false + default: + log.Printf("WARNING: type %q is not portable: %s", t.Kind, t.Name) + return false + } +} + +// isOptionalAlias should return true if the specified type has an underlying type +// (is an alias) of a map or slice and has the comment tag protobuf.nullable=true, +// indicating that the type should be nullable in protobuf. +func isOptionalAlias(t *types.Type) bool { + if t.Underlying == nil || (t.Underlying.Kind != types.Map && t.Underlying.Kind != types.Slice) { + return false + } + if extractBoolTagOrDie("protobuf.nullable", t.CommentLines) == false { + return false + } + return true +} + +func (g *genProtoIDL) Imports(c *generator.Context) (imports []string) { + lines := []string{} + // TODO: this could be expressed more cleanly + for _, line := range g.imports.ImportLines() { + if g.omitGogo && line == "github.com/gogo/protobuf/gogoproto/gogo.proto" { + continue + } + lines = append(lines, line) + } + return lines +} + +// GenerateType makes the body of a file implementing a set for type t. +func (g *genProtoIDL) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + b := bodyGen{ + locator: &protobufLocator{ + namer: c.Namers["proto"].(ProtobufFromGoNamer), + tracker: g.imports, + universe: c.Universe, + + localGoPackage: g.localGoPackage.Package, + }, + localPackage: g.localPackage, + + omitGogo: g.omitGogo, + omitFieldTypes: g.omitFieldTypes, + + t: t, + } + switch t.Kind { + case types.Alias: + return b.doAlias(sw) + case types.Struct: + return b.doStruct(sw) + default: + return b.unknown(sw) + } +} + +// ProtobufFromGoNamer finds the protobuf name of a type (and its package, and +// the package path) from its Go name. +type ProtobufFromGoNamer interface { + GoNameToProtoName(name types.Name) types.Name +} + +type ProtobufLocator interface { + ProtoTypeFor(t *types.Type) (*types.Type, error) + GoTypeForName(name types.Name) *types.Type + CastTypeName(name types.Name) string +} + +type protobufLocator struct { + namer ProtobufFromGoNamer + tracker namer.ImportTracker + universe types.Universe + + localGoPackage string +} + +// CastTypeName returns the cast type name of a Go type +// TODO: delegate to a new localgo namer? +func (p protobufLocator) CastTypeName(name types.Name) string { + if name.Package == p.localGoPackage { + return name.Name + } + return name.String() +} + +func (p protobufLocator) GoTypeForName(name types.Name) *types.Type { + if len(name.Package) == 0 { + name.Package = p.localGoPackage + } + return p.universe.Type(name) +} + +// ProtoTypeFor locates a Protobuf type for the provided Go type (if possible). +func (p protobufLocator) ProtoTypeFor(t *types.Type) (*types.Type, error) { + // we've already converted the type, or it's a map + if t.Kind == types.Protobuf || t.Kind == types.Map { + p.tracker.AddType(t) + return t, nil + } + // it's a fundamental type + if t, ok := isFundamentalProtoType(t); ok { + p.tracker.AddType(t) + return t, nil + } + // it's a message + if t.Kind == types.Struct || isOptionalAlias(t) { + t := &types.Type{ + Name: p.namer.GoNameToProtoName(t.Name), + Kind: types.Protobuf, + + CommentLines: t.CommentLines, + } + p.tracker.AddType(t) + return t, nil + } + return nil, errUnrecognizedType +} + +type bodyGen struct { + locator ProtobufLocator + localPackage types.Name + omitGogo bool + omitFieldTypes map[types.Name]struct{} + + t *types.Type +} + +func (b bodyGen) unknown(sw *generator.SnippetWriter) error { + return fmt.Errorf("not sure how to generate: %#v", b.t) +} + +func (b bodyGen) doAlias(sw *generator.SnippetWriter) error { + if !isOptionalAlias(b.t) { + return nil + } + + var kind string + switch b.t.Underlying.Kind { + case types.Map: + kind = "map" + default: + kind = "slice" + } + optional := &types.Type{ + Name: b.t.Name, + Kind: types.Struct, + + CommentLines: b.t.CommentLines, + SecondClosestCommentLines: b.t.SecondClosestCommentLines, + Members: []types.Member{ + { + Name: "Items", + CommentLines: []string{fmt.Sprintf("items, if empty, will result in an empty %s\n", kind)}, + Type: b.t.Underlying, + }, + }, + } + nested := b + nested.t = optional + return nested.doStruct(sw) +} + +func (b bodyGen) doStruct(sw *generator.SnippetWriter) error { + if len(b.t.Name.Name) == 0 { + return nil + } + if namer.IsPrivateGoName(b.t.Name.Name) { + return nil + } + + var alias *types.Type + var fields []protoField + options := []string{} + allOptions := gengo.ExtractCommentTags("+", b.t.CommentLines) + for k, v := range allOptions { + switch { + case strings.HasPrefix(k, "protobuf.options."): + key := strings.TrimPrefix(k, "protobuf.options.") + switch key { + case "marshal": + if v[0] == "false" { + if !b.omitGogo { + options = append(options, + "(gogoproto.marshaler) = false", + "(gogoproto.unmarshaler) = false", + "(gogoproto.sizer) = false", + ) + } + } + default: + if !b.omitGogo || !strings.HasPrefix(key, "(gogoproto.") { + if key == "(gogoproto.goproto_stringer)" && v[0] == "false" { + options = append(options, "(gogoproto.stringer) = false") + } + options = append(options, fmt.Sprintf("%s = %s", key, v[0])) + } + } + // protobuf.as allows a type to have the same message contents as another Go type + case k == "protobuf.as": + fields = nil + if alias = b.locator.GoTypeForName(types.Name{Name: v[0]}); alias == nil { + return fmt.Errorf("type %v references alias %q which does not exist", b.t, v[0]) + } + // protobuf.embed instructs the generator to use the named type in this package + // as an embedded message. + case k == "protobuf.embed": + fields = []protoField{ + { + Tag: 1, + Name: v[0], + Type: &types.Type{ + Name: types.Name{ + Name: v[0], + Package: b.localPackage.Package, + Path: b.localPackage.Path, + }, + }, + }, + } + } + } + if alias == nil { + alias = b.t + } + + // If we don't explicitly embed anything, generate fields by traversing fields. + if fields == nil { + memberFields, err := membersToFields(b.locator, alias, b.localPackage, b.omitFieldTypes) + if err != nil { + return fmt.Errorf("type %v cannot be converted to protobuf: %v", b.t, err) + } + fields = memberFields + } + + out := sw.Out() + genComment(out, b.t.CommentLines, "") + sw.Do(`message $.Name.Name$ { +`, b.t) + + if len(options) > 0 { + sort.Strings(options) + for _, s := range options { + fmt.Fprintf(out, " option %s;\n", s) + } + fmt.Fprintln(out) + } + + for i, field := range fields { + genComment(out, field.CommentLines, " ") + fmt.Fprintf(out, " ") + switch { + case field.Map: + case field.Repeated: + fmt.Fprintf(out, "repeated ") + case field.Required: + fmt.Fprintf(out, "required ") + default: + fmt.Fprintf(out, "optional ") + } + sw.Do(`$.Type|local$ $.Name$ = $.Tag$`, field) + if len(field.Extras) > 0 { + extras := []string{} + for k, v := range field.Extras { + if b.omitGogo && strings.HasPrefix(k, "(gogoproto.") { + continue + } + extras = append(extras, fmt.Sprintf("%s = %s", k, v)) + } + sort.Strings(extras) + if len(extras) > 0 { + fmt.Fprintf(out, " [") + fmt.Fprint(out, strings.Join(extras, ", ")) + fmt.Fprintf(out, "]") + } + } + fmt.Fprintf(out, ";\n") + if i != len(fields)-1 { + fmt.Fprintf(out, "\n") + } + } + fmt.Fprintf(out, "}\n\n") + return nil +} + +type protoField struct { + LocalPackage types.Name + + Tag int + Name string + Type *types.Type + Map bool + Repeated bool + Optional bool + Required bool + Nullable bool + Extras map[string]string + + CommentLines []string +} + +var ( + errUnrecognizedType = fmt.Errorf("did not recognize the provided type") +) + +func isFundamentalProtoType(t *types.Type) (*types.Type, bool) { + // TODO: when we enable proto3, also include other fundamental types in the google.protobuf package + // switch { + // case t.Kind == types.Struct && t.Name == types.Name{Package: "time", Name: "Time"}: + // return &types.Type{ + // Kind: types.Protobuf, + // Name: types.Name{Path: "google/protobuf/timestamp.proto", Package: "google.protobuf", Name: "Timestamp"}, + // }, true + // } + switch t.Kind { + case types.Slice: + if t.Elem.Name.Name == "byte" && len(t.Elem.Name.Package) == 0 { + return &types.Type{Name: types.Name{Name: "bytes"}, Kind: types.Protobuf}, true + } + case types.Builtin: + switch t.Name.Name { + case "string", "uint32", "int32", "uint64", "int64", "bool": + return &types.Type{Name: types.Name{Name: t.Name.Name}, Kind: types.Protobuf}, true + case "int": + return &types.Type{Name: types.Name{Name: "int64"}, Kind: types.Protobuf}, true + case "uint": + return &types.Type{Name: types.Name{Name: "uint64"}, Kind: types.Protobuf}, true + case "float64", "float": + return &types.Type{Name: types.Name{Name: "double"}, Kind: types.Protobuf}, true + case "float32": + return &types.Type{Name: types.Name{Name: "float"}, Kind: types.Protobuf}, true + case "uintptr": + return &types.Type{Name: types.Name{Name: "uint64"}, Kind: types.Protobuf}, true + } + // TODO: complex? + } + return t, false +} + +func memberTypeToProtobufField(locator ProtobufLocator, field *protoField, t *types.Type) error { + var err error + switch t.Kind { + case types.Protobuf: + field.Type, err = locator.ProtoTypeFor(t) + case types.Builtin: + field.Type, err = locator.ProtoTypeFor(t) + case types.Map: + valueField := &protoField{} + if err := memberTypeToProtobufField(locator, valueField, t.Elem); err != nil { + return err + } + keyField := &protoField{} + if err := memberTypeToProtobufField(locator, keyField, t.Key); err != nil { + return err + } + // All other protobuf types have kind types.Protobuf, so setting types.Map + // here would be very misleading. + field.Type = &types.Type{ + Kind: types.Protobuf, + Key: keyField.Type, + Elem: valueField.Type, + } + if !strings.HasPrefix(t.Name.Name, "map[") { + field.Extras["(gogoproto.casttype)"] = strconv.Quote(locator.CastTypeName(t.Name)) + } + if k, ok := keyField.Extras["(gogoproto.casttype)"]; ok { + field.Extras["(gogoproto.castkey)"] = k + } + if v, ok := valueField.Extras["(gogoproto.casttype)"]; ok { + field.Extras["(gogoproto.castvalue)"] = v + } + field.Map = true + case types.Pointer: + if err := memberTypeToProtobufField(locator, field, t.Elem); err != nil { + return err + } + field.Nullable = true + case types.Alias: + if isOptionalAlias(t) { + field.Type, err = locator.ProtoTypeFor(t) + field.Nullable = true + } else { + if err := memberTypeToProtobufField(locator, field, t.Underlying); err != nil { + log.Printf("failed to alias: %s %s: err %v", t.Name, t.Underlying.Name, err) + return err + } + // If this is not an alias to a slice, cast to the alias + if !field.Repeated { + if field.Extras == nil { + field.Extras = make(map[string]string) + } + field.Extras["(gogoproto.casttype)"] = strconv.Quote(locator.CastTypeName(t.Name)) + } + } + case types.Slice: + if t.Elem.Name.Name == "byte" && len(t.Elem.Name.Package) == 0 { + field.Type = &types.Type{Name: types.Name{Name: "bytes"}, Kind: types.Protobuf} + return nil + } + if err := memberTypeToProtobufField(locator, field, t.Elem); err != nil { + return err + } + field.Repeated = true + case types.Struct: + if len(t.Name.Name) == 0 { + return errUnrecognizedType + } + field.Type, err = locator.ProtoTypeFor(t) + field.Nullable = false + default: + return errUnrecognizedType + } + return err +} + +// protobufTagToField extracts information from an existing protobuf tag +func protobufTagToField(tag string, field *protoField, m types.Member, t *types.Type, localPackage types.Name) error { + if len(tag) == 0 || tag == "-" { + return nil + } + + // protobuf:"bytes,3,opt,name=Id,customtype=github.com/gogo/protobuf/test.Uuid" + parts := strings.Split(tag, ",") + if len(parts) < 3 { + return fmt.Errorf("member %q of %q malformed 'protobuf' tag, not enough segments", m.Name, t.Name) + } + protoTag, err := strconv.Atoi(parts[1]) + if err != nil { + return fmt.Errorf("member %q of %q malformed 'protobuf' tag, field ID is %q which is not an integer: %w", m.Name, t.Name, parts[1], err) + } + field.Tag = protoTag + + // In general there is doesn't make sense to parse the protobuf tags to get the type, + // as all auto-generated once will have wire type "bytes", "varint" or "fixed64". + // However, sometimes we explicitly set them to have a custom serialization, e.g.: + // type Time struct { + // time.Time `protobuf:"Timestamp,1,req,name=time"` + // } + // to force the generator to use a given type (that we manually wrote serialization & + // deserialization methods for). + switch parts[0] { + case "varint", "fixed32", "fixed64", "bytes", "group": + default: + var name types.Name + if last := strings.LastIndex(parts[0], "."); last != -1 { + prefix := parts[0][:last] + name = types.Name{ + Name: parts[0][last+1:], + Package: prefix, + Path: strings.ReplaceAll(prefix, ".", "/"), + } + } else { + name = types.Name{ + Name: parts[0], + Package: localPackage.Package, + Path: localPackage.Path, + } + } + field.Type = &types.Type{ + Name: name, + Kind: types.Protobuf, + } + } + + protoExtra := make(map[string]string) + for i, extra := range parts[3:] { + parts := strings.SplitN(extra, "=", 2) + if len(parts) != 2 { + return fmt.Errorf("member %q of %q malformed 'protobuf' tag, tag %d should be key=value, got %q", m.Name, t.Name, i+4, extra) + } + switch parts[0] { + case "name": + protoExtra[parts[0]] = parts[1] + case "casttype", "castkey", "castvalue": + parts[0] = fmt.Sprintf("(gogoproto.%s)", parts[0]) + protoExtra[parts[0]] = strconv.Quote(parts[1]) + } + } + + field.Extras = protoExtra + if name, ok := protoExtra["name"]; ok { + field.Name = name + delete(protoExtra, "name") + } + + return nil +} + +func membersToFields(locator ProtobufLocator, t *types.Type, localPackage types.Name, omitFieldTypes map[types.Name]struct{}) ([]protoField, error) { + fields := []protoField{} + + for _, m := range t.Members { + if namer.IsPrivateGoName(m.Name) { + // skip private fields + continue + } + if _, ok := omitFieldTypes[types.Name{Name: m.Type.Name.Name, Package: m.Type.Name.Package}]; ok { + continue + } + tags := reflect.StructTag(m.Tags) + field := protoField{ + LocalPackage: localPackage, + + Tag: -1, + Extras: make(map[string]string), + } + + protobufTag := tags.Get("protobuf") + if protobufTag == "-" { + continue + } + + if err := protobufTagToField(protobufTag, &field, m, t, localPackage); err != nil { + return nil, err + } + + // extract information from JSON field tag + if tag := tags.Get("json"); len(tag) > 0 { + parts := strings.Split(tag, ",") + if len(field.Name) == 0 && len(parts[0]) != 0 { + field.Name = parts[0] + } + if field.Tag == -1 && field.Name == "-" { + continue + } + } + + if field.Type == nil { + if err := memberTypeToProtobufField(locator, &field, m.Type); err != nil { + return nil, fmt.Errorf("unable to embed type %q as field %q in %q: %v", m.Type, field.Name, t.Name, err) + } + } + if len(field.Name) == 0 { + field.Name = namer.IL(m.Name) + } + + if field.Map && field.Repeated { + // maps cannot be repeated + field.Repeated = false + field.Nullable = true + } + + if !field.Nullable { + field.Extras["(gogoproto.nullable)"] = "false" + } + if (field.Type.Name.Name == "bytes" && field.Type.Name.Package == "") || (field.Repeated && field.Type.Name.Package == "" && namer.IsPrivateGoName(field.Type.Name.Name)) { + delete(field.Extras, "(gogoproto.nullable)") + } + if field.Name != m.Name { + field.Extras["(gogoproto.customname)"] = strconv.Quote(m.Name) + } + field.CommentLines = m.CommentLines + fields = append(fields, field) + } + + // assign tags + highest := 0 + byTag := make(map[int]*protoField) + // fields are in Go struct order, which we preserve + for i := range fields { + field := &fields[i] + tag := field.Tag + if tag != -1 { + if existing, ok := byTag[tag]; ok { + return nil, fmt.Errorf("field %q and %q both have tag %d", field.Name, existing.Name, tag) + } + byTag[tag] = field + } + if tag > highest { + highest = tag + } + } + // starting from the highest observed tag, assign new field tags + for i := range fields { + field := &fields[i] + if field.Tag != -1 { + continue + } + highest++ + field.Tag = highest + byTag[field.Tag] = field + } + return fields, nil +} + +func genComment(out io.Writer, lines []string, indent string) { + for { + l := len(lines) + if l == 0 || len(lines[l-1]) != 0 { + break + } + lines = lines[:l-1] + } + for _, c := range lines { + if len(c) == 0 { + fmt.Fprintf(out, "%s//\n", indent) // avoid trailing whitespace + continue + } + fmt.Fprintf(out, "%s// %s\n", indent, c) + } +} + +func formatProtoFile(source []byte) ([]byte, error) { + // TODO; Is there any protobuf formatter? + return source, nil +} + +func assembleProtoFile(w io.Writer, f *generator.File) { + w.Write(f.Header) + + fmt.Fprint(w, "syntax = \"proto2\";\n\n") + + if len(f.PackageName) > 0 { + fmt.Fprintf(w, "package %s;\n\n", f.PackageName) + } + + if len(f.Imports) > 0 { + imports := []string{} + for i := range f.Imports { + imports = append(imports, i) + } + sort.Strings(imports) + for _, s := range imports { + fmt.Fprintf(w, "import %q;\n", s) + } + fmt.Fprint(w, "\n") + } + + if f.Vars.Len() > 0 { + fmt.Fprintf(w, "%s\n", f.Vars.String()) + } + + w.Write(f.Body.Bytes()) +} + +func NewProtoFile() *generator.DefaultFileType { + return &generator.DefaultFileType{ + Format: formatProtoFile, + Assemble: assembleProtoFile, + } +} diff --git a/code-generator/cmd/go-to-protobuf/protobuf/import_tracker.go b/code-generator/cmd/go-to-protobuf/protobuf/import_tracker.go new file mode 100644 index 000000000..0031c9bd8 --- /dev/null +++ b/code-generator/cmd/go-to-protobuf/protobuf/import_tracker.go @@ -0,0 +1,50 @@ +/* +Copyright 2015 The Kubernetes 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 protobuf + +import ( + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" +) + +type ImportTracker struct { + namer.DefaultImportTracker +} + +func NewImportTracker(local types.Name, typesToAdd ...*types.Type) *ImportTracker { + tracker := namer.NewDefaultImportTracker(local) + tracker.IsInvalidType = func(t *types.Type) bool { return t.Kind != types.Protobuf } + tracker.LocalName = func(name types.Name) string { return name.Package } + tracker.PrintImport = func(path, name string) string { return path } + + tracker.AddTypes(typesToAdd...) + return &ImportTracker{ + DefaultImportTracker: tracker, + } +} + +// AddNullable ensures that support for the nullable Gogo-protobuf extension is added. +func (tracker *ImportTracker) AddNullable() { + tracker.AddType(&types.Type{ + Kind: types.Protobuf, + Name: types.Name{ + Name: "nullable", + Package: "gogoproto", + Path: "github.com/gogo/protobuf/gogoproto/gogo.proto", + }, + }) +} diff --git a/code-generator/cmd/go-to-protobuf/protobuf/namer.go b/code-generator/cmd/go-to-protobuf/protobuf/namer.go new file mode 100644 index 000000000..2ad0a9537 --- /dev/null +++ b/code-generator/cmd/go-to-protobuf/protobuf/namer.go @@ -0,0 +1,206 @@ +/* +Copyright 2015 The Kubernetes 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 protobuf + +import ( + "fmt" + "reflect" + "strings" + + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" +) + +type localNamer struct { + localPackage types.Name +} + +func (n localNamer) Name(t *types.Type) string { + if t.Key != nil && t.Elem != nil { + return fmt.Sprintf("map<%s, %s>", n.Name(t.Key), n.Name(t.Elem)) + } + if len(n.localPackage.Package) != 0 && n.localPackage.Package == t.Name.Package { + return t.Name.Name + } + // For non-local and non-fundamental types, use an absolute reference + // see https://protobuf.com/docs/language-spec#type-references + if strings.Contains(t.Name.Package, ".") { + return fmt.Sprintf(".%s", t.Name) + } + return t.Name.String() +} + +type protobufNamer struct { + packages []*protobufPackage + // The key here is a Go import-path. + packagesByPath map[string]*protobufPackage +} + +func NewProtobufNamer() *protobufNamer { + return &protobufNamer{ + packagesByPath: make(map[string]*protobufPackage), + } +} + +func (n *protobufNamer) Name(t *types.Type) string { + if t.Kind == types.Map { + return fmt.Sprintf("map<%s, %s>", n.Name(t.Key), n.Name(t.Elem)) + } + return t.Name.String() +} + +func (n *protobufNamer) Add(p *protobufPackage) { + if _, ok := n.packagesByPath[p.Path()]; !ok { + n.packagesByPath[p.Path()] = p + n.packages = append(n.packages, p) + } +} + +func (n *protobufNamer) GoNameToProtoName(name types.Name) types.Name { + if p, ok := n.packagesByPath[name.Package]; ok { + return types.Name{ + Name: name.Name, + Package: p.Name(), + Path: p.ImportPath(), + } + } + for _, p := range n.packages { + if _, ok := p.FilterTypes[name]; ok { + return types.Name{ + Name: name.Name, + Package: p.Name(), + Path: p.ImportPath(), + } + } + } + return types.Name{Name: name.Name} +} + +func protoSafePackage(name string) string { + pkg := strings.ReplaceAll(name, "/", ".") + return strings.ReplaceAll(pkg, "-", "_") +} + +type typeNameSet map[types.Name]*protobufPackage + +// assignGoTypeToProtoPackage looks for Go and Protobuf types that are referenced by a type in +// a package. It will not recurse into protobuf types. +func assignGoTypeToProtoPackage(p *protobufPackage, t *types.Type, local, global typeNameSet, optional map[types.Name]struct{}) { + newT, isProto := isFundamentalProtoType(t) + if isProto { + t = newT + } + if otherP, ok := global[t.Name]; ok { + if _, ok := local[t.Name]; !ok { + p.Imports.AddType(&types.Type{ + Kind: types.Protobuf, + Name: otherP.ProtoTypeName(), + }) + } + return + } + if t.Name.Package == p.Path() { + // Associate types only to their own package + global[t.Name] = p + } + if _, ok := local[t.Name]; ok { + return + } + // don't recurse into existing proto types + if isProto { + p.Imports.AddType(t) + return + } + + local[t.Name] = p + for _, m := range t.Members { + if namer.IsPrivateGoName(m.Name) { + continue + } + field := &protoField{} + tag := reflect.StructTag(m.Tags).Get("protobuf") + if tag == "-" { + continue + } + if err := protobufTagToField(tag, field, m, t, p.ProtoTypeName()); err == nil && field.Type != nil { + assignGoTypeToProtoPackage(p, field.Type, local, global, optional) + continue + } + assignGoTypeToProtoPackage(p, m.Type, local, global, optional) + } + // TODO: should methods be walked? + if t.Elem != nil { + assignGoTypeToProtoPackage(p, t.Elem, local, global, optional) + } + if t.Key != nil { + assignGoTypeToProtoPackage(p, t.Key, local, global, optional) + } + if t.Underlying != nil { + if t.Kind == types.Alias && isOptionalAlias(t) { + optional[t.Name] = struct{}{} + } + assignGoTypeToProtoPackage(p, t.Underlying, local, global, optional) + } +} + +// isTypeApplicableToProtobuf checks to see if a type is relevant for protobuf processing. +// Currently, it filters out functions and private types. +func isTypeApplicableToProtobuf(t *types.Type) bool { + // skip functions -- we don't care about them for protobuf + if t.Kind == types.Func || (t.Kind == types.DeclarationOf && t.Underlying.Kind == types.Func) { + return false + } + // skip private types + if namer.IsPrivateGoName(t.Name.Name) { + return false + } + + return true +} + +func (n *protobufNamer) AssignTypesToPackages(c *generator.Context) error { + global := make(typeNameSet) + for _, p := range n.packages { + local := make(typeNameSet) + optional := make(map[types.Name]struct{}) + p.Imports = NewImportTracker(p.ProtoTypeName()) + for _, t := range c.Order { + if t.Name.Package != p.Path() { + continue + } + if !isTypeApplicableToProtobuf(t) { + // skip types that we don't care about, like functions + continue + } + assignGoTypeToProtoPackage(p, t, local, global, optional) + } + p.FilterTypes = make(map[types.Name]struct{}) + p.LocalNames = make(map[string]struct{}) + p.OptionalTypeNames = make(map[string]struct{}) + for k, v := range local { + if v == p { + p.FilterTypes[k] = struct{}{} + p.LocalNames[k.Name] = struct{}{} + if _, ok := optional[k]; ok { + p.OptionalTypeNames[k.Name] = struct{}{} + } + } + } + } + return nil +} diff --git a/code-generator/cmd/go-to-protobuf/protobuf/namer_test.go b/code-generator/cmd/go-to-protobuf/protobuf/namer_test.go new file mode 100644 index 000000000..0ee71f80b --- /dev/null +++ b/code-generator/cmd/go-to-protobuf/protobuf/namer_test.go @@ -0,0 +1,50 @@ +/* +Copyright 2016 The Kubernetes 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 protobuf + +import "testing" + +func TestProtoSafePackage(t *testing.T) { + tests := []struct { + pkg string + expected string + }{ + { + pkg: "foo", + expected: "foo", + }, + { + pkg: "foo/bar", + expected: "foo.bar", + }, + { + pkg: "foo/bar/baz", + expected: "foo.bar.baz", + }, + { + pkg: "foo/bar-baz/x/y-z/q", + expected: "foo.bar_baz.x.y_z.q", + }, + } + + for _, test := range tests { + actual := protoSafePackage(test.pkg) + if e, a := test.expected, actual; e != a { + t.Errorf("%s: expected %s, got %s", test.pkg, e, a) + } + } +} diff --git a/code-generator/cmd/go-to-protobuf/protobuf/package.go b/code-generator/cmd/go-to-protobuf/protobuf/package.go new file mode 100644 index 000000000..b31a7c4dd --- /dev/null +++ b/code-generator/cmd/go-to-protobuf/protobuf/package.go @@ -0,0 +1,205 @@ +/* +Copyright 2015 The Kubernetes 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 protobuf + +import ( + "fmt" + "go/ast" + "log" + "os" + "path/filepath" + "reflect" + "strings" + + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/types" +) + +func newProtobufPackage(packagePath, packageDir, packageName string, generateAll bool, omitFieldTypes map[types.Name]struct{}) *protobufPackage { + pkg := &protobufPackage{ + SimpleTarget: generator.SimpleTarget{ + // The protobuf package name (foo.bar.baz) + PkgName: packageName, + PkgPath: packagePath, + PkgDir: packageDir, + HeaderComment: []byte("// This file was autogenerated by go-to-protobuf. Do not edit it manually!\n\n"), + PkgDocComment: []byte(fmt.Sprintf("// Package %s is an autogenerated protobuf IDL.\n", packageName)), + }, + GenerateAll: generateAll, + OmitFieldTypes: omitFieldTypes, + } + pkg.FilterFunc = pkg.filterFunc + pkg.GeneratorsFunc = pkg.generatorsFunc + return pkg +} + +// protobufPackage contains the protobuf implementation of Package. +type protobufPackage struct { + generator.SimpleTarget + + // If true, generate protobuf serializations for all public types. + // If false, only generate protobuf serializations for structs that + // request serialization. + GenerateAll bool + + // A list of types to filter to; if not specified all types will be included. + FilterTypes map[types.Name]struct{} + + // If true, omit any gogoprotobuf extensions not defined as types. + OmitGogo bool + + // A list of field types that will be excluded from the output struct + OmitFieldTypes map[types.Name]struct{} + + // A list of names that this package exports + LocalNames map[string]struct{} + + // A list of type names in this package that will need marshaller rewriting + // to remove synthetic protobuf fields. + OptionalTypeNames map[string]struct{} + + // A list of struct tags to generate onto named struct fields + StructTags map[string]map[string]string + + // An import tracker for this package + Imports *ImportTracker +} + +func (p *protobufPackage) Clean() error { + for _, s := range []string{p.ImportPath(), p.OutputPath()} { + if err := os.Remove(filepath.Join(p.Dir(), filepath.Base(s))); err != nil && !os.IsNotExist(err) { + return err + } + } + return nil +} + +func (p *protobufPackage) ProtoTypeName() types.Name { + return types.Name{ + Name: p.Path(), // the go path "foo/bar/baz" + Package: p.Name(), // the protobuf package "foo.bar.baz" + Path: p.ImportPath(), // the path of the import to get the proto + } +} + +func (p *protobufPackage) filterFunc(c *generator.Context, t *types.Type) bool { + switch t.Kind { + case types.Func, types.Chan: + return false + case types.Struct: + if t.Name.Name == "struct{}" { + return false + } + case types.Builtin: + return false + case types.Alias: + if !isOptionalAlias(t) { + return false + } + case types.Slice, types.Array, types.Map: + return false + case types.Pointer: + return false + } + if _, ok := isFundamentalProtoType(t); ok { + return false + } + _, ok := p.FilterTypes[t.Name] + return ok +} + +func (p *protobufPackage) HasGoType(name string) bool { + _, ok := p.LocalNames[name] + return ok +} + +func (p *protobufPackage) OptionalTypeName(name string) bool { + _, ok := p.OptionalTypeNames[name] + return ok +} + +func (p *protobufPackage) ExtractGeneratedType(t *ast.TypeSpec) bool { + if !p.HasGoType(t.Name.Name) { + return false + } + + switch s := t.Type.(type) { + case *ast.StructType: + for i, f := range s.Fields.List { + if len(f.Tag.Value) == 0 { + continue + } + tag := strings.Trim(f.Tag.Value, "`") + protobufTag := reflect.StructTag(tag).Get("protobuf") + if len(protobufTag) == 0 { + continue + } + if len(f.Names) > 1 { + log.Printf("WARNING: struct %s field %d %s: defined multiple names but single protobuf tag", t.Name.Name, i, f.Names[0].Name) + // TODO hard error? + } + if p.StructTags == nil { + p.StructTags = make(map[string]map[string]string) + } + m := p.StructTags[t.Name.Name] + if m == nil { + m = make(map[string]string) + p.StructTags[t.Name.Name] = m + } + m[f.Names[0].Name] = tag + } + default: + log.Printf("WARNING: unexpected Go AST type definition: %#v", t) + } + + return true +} + +func (p *protobufPackage) generatorsFunc(c *generator.Context) []generator.Generator { + generators := []generator.Generator{} + + p.Imports.AddNullable() + + generators = append(generators, &genProtoIDL{ + GoGenerator: generator.GoGenerator{ + OutputFilename: "generated", // the extension is added later + }, + localPackage: types.Name{Package: p.Name(), Path: p.Path()}, + localGoPackage: types.Name{Package: p.Path(), Name: p.GoPackageName()}, + imports: p.Imports, + generateAll: p.GenerateAll, + omitGogo: p.OmitGogo, + omitFieldTypes: p.OmitFieldTypes, + }) + return generators +} + +func (p *protobufPackage) GoPackageName() string { + return filepath.Base(p.Path()) +} + +func (p *protobufPackage) ImportPath() string { + return filepath.Join(p.Path(), "generated.proto") +} + +func (p *protobufPackage) OutputPath() string { + return filepath.Join(p.Path(), "generated.pb.go") +} + +var ( + _ = generator.Target(&protobufPackage{}) +) diff --git a/code-generator/cmd/go-to-protobuf/protobuf/parser.go b/code-generator/cmd/go-to-protobuf/protobuf/parser.go new file mode 100644 index 000000000..32f9e0da2 --- /dev/null +++ b/code-generator/cmd/go-to-protobuf/protobuf/parser.go @@ -0,0 +1,453 @@ +/* +Copyright 2015 The Kubernetes 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 protobuf + +import ( + "bytes" + "errors" + "fmt" + "go/ast" + "go/format" + "go/parser" + "go/printer" + "go/token" + "os" + "reflect" + "strings" + + customreflect "k8s.io/code-generator/third_party/forked/golang/reflect" +) + +func rewriteFile(name string, header []byte, rewriteFn func(*token.FileSet, *ast.File) error) error { + fset := token.NewFileSet() + src, err := os.ReadFile(name) + if err != nil { + return err + } + file, err := parser.ParseFile(fset, name, src, parser.DeclarationErrors|parser.ParseComments) + if err != nil { + return err + } + + if err := rewriteFn(fset, file); err != nil { + return err + } + + b := &bytes.Buffer{} + b.Write(header) + if err := printer.Fprint(b, fset, file); err != nil { + return err + } + + body, err := format.Source(b.Bytes()) + if err != nil { + return err + } + + f, err := os.OpenFile(name, os.O_WRONLY|os.O_TRUNC, 0644) + if err != nil { + return err + } + defer f.Close() + if _, err := f.Write(body); err != nil { + return err + } + return f.Close() +} + +// ExtractFunc extracts information from the provided TypeSpec and returns true if the type should be +// removed from the destination file. +type ExtractFunc func(*ast.TypeSpec) bool + +// OptionalFunc returns true if the provided local name is a type that has protobuf.nullable=true +// and should have its marshal functions adjusted to remove the 'Items' accessor. +type OptionalFunc func(name string) bool + +func RewriteGeneratedGogoProtobufFile(name string, extractFn ExtractFunc, optionalFn OptionalFunc, header []byte) error { + return rewriteFile(name, header, func(fset *token.FileSet, file *ast.File) error { + cmap := ast.NewCommentMap(fset, file, file.Comments) + + // transform methods that point to optional maps or slices + for _, d := range file.Decls { + rewriteOptionalMethods(d, optionalFn) + } + + // remove types that are already declared + decls := []ast.Decl{} + for _, d := range file.Decls { + if dropExistingTypeDeclarations(d, extractFn) { + continue + } + if dropEmptyImportDeclarations(d) { + continue + } + decls = append(decls, d) + } + file.Decls = decls + + // remove unmapped comments + file.Comments = cmap.Filter(file).Comments() + return nil + }) +} + +// rewriteOptionalMethods makes specific mutations to marshaller methods that belong to types identified +// as being "optional" (they may be nil on the wire). This allows protobuf to serialize a map or slice and +// properly discriminate between empty and nil (which is not possible in protobuf). +// TODO: move into upstream gogo-protobuf once https://github.com/gogo/protobuf/issues/181 +// has agreement +func rewriteOptionalMethods(decl ast.Decl, isOptional OptionalFunc) { + if t, ok := decl.(*ast.FuncDecl); ok { + ident, ptr, ok := receiver(t) + if !ok { + return + } + + // correct initialization of the form `m.Field = &OptionalType{}` to + // `m.Field = OptionalType{}` + if t.Name.Name == "Unmarshal" { + ast.Walk(optionalAssignmentVisitor{fn: isOptional}, t.Body) + } + + if !isOptional(ident.Name) { + return + } + + switch t.Name.Name { + case "Unmarshal": + ast.Walk(&optionalItemsVisitor{}, t.Body) + case "MarshalTo", "Size", "String", "MarshalToSizedBuffer": + ast.Walk(&optionalItemsVisitor{}, t.Body) + fallthrough + case "Marshal": + // if the method has a pointer receiver, set it back to a normal receiver + if ptr { + t.Recv.List[0].Type = ident + } + } + } +} + +type optionalAssignmentVisitor struct { + fn OptionalFunc +} + +// Visit walks the provided node, transforming field initializations of the form +// m.Field = &OptionalType{} -> m.Field = OptionalType{} +func (v optionalAssignmentVisitor) Visit(n ast.Node) ast.Visitor { + if t, ok := n.(*ast.AssignStmt); ok { + if len(t.Lhs) == 1 && len(t.Rhs) == 1 { + if !isFieldSelector(t.Lhs[0], "m", "") { + return nil + } + unary, ok := t.Rhs[0].(*ast.UnaryExpr) + if !ok || unary.Op != token.AND { + return nil + } + composite, ok := unary.X.(*ast.CompositeLit) + if !ok || composite.Type == nil || len(composite.Elts) != 0 { + return nil + } + if ident, ok := composite.Type.(*ast.Ident); ok && v.fn(ident.Name) { + t.Rhs[0] = composite + } + } + return nil + } + return v +} + +type optionalItemsVisitor struct{} + +// Visit walks the provided node, looking for specific patterns to transform that match +// the effective outcome of turning struct{ map[x]y || []x } into map[x]y or []x. +func (v *optionalItemsVisitor) Visit(n ast.Node) ast.Visitor { + switch t := n.(type) { + case *ast.RangeStmt: + if isFieldSelector(t.X, "m", "Items") { + t.X = &ast.Ident{Name: "m"} + } + case *ast.AssignStmt: + if len(t.Lhs) == 1 && len(t.Rhs) == 1 { + switch lhs := t.Lhs[0].(type) { + case *ast.IndexExpr: + if isFieldSelector(lhs.X, "m", "Items") { + lhs.X = &ast.StarExpr{X: &ast.Ident{Name: "m"}} + } + default: + if isFieldSelector(t.Lhs[0], "m", "Items") { + t.Lhs[0] = &ast.StarExpr{X: &ast.Ident{Name: "m"}} + } + } + if rhs, ok := t.Rhs[0].(*ast.CallExpr); ok { + if ident, ok := rhs.Fun.(*ast.Ident); ok && ident.Name == "append" { + ast.Walk(v, rhs) + if len(rhs.Args) > 0 { + if arg, ok := rhs.Args[0].(*ast.Ident); ok { + if arg.Name == "m" { + rhs.Args[0] = &ast.StarExpr{X: &ast.Ident{Name: "m"}} + } + } + } + return nil + } + } + } + case *ast.IfStmt: + if cond, ok := t.Cond.(*ast.BinaryExpr); ok { + if cond.Op == token.EQL { + if isFieldSelector(cond.X, "m", "Items") && isIdent(cond.Y, "nil") { + cond.X = &ast.StarExpr{X: &ast.Ident{Name: "m"}} + } + } + } + if t.Init != nil { + // Find form: + // if err := m[len(m.Items)-1].Unmarshal(data[iNdEx:postIndex]); err != nil { + // return err + // } + if s, ok := t.Init.(*ast.AssignStmt); ok { + if call, ok := s.Rhs[0].(*ast.CallExpr); ok { + if sel, ok := call.Fun.(*ast.SelectorExpr); ok { + if x, ok := sel.X.(*ast.IndexExpr); ok { + // m[] -> (*m)[] + if sel2, ok := x.X.(*ast.SelectorExpr); ok { + if ident, ok := sel2.X.(*ast.Ident); ok && ident.Name == "m" { + x.X = &ast.StarExpr{X: &ast.Ident{Name: "m"}} + } + } + // len(m.Items) -> len(*m) + if bin, ok := x.Index.(*ast.BinaryExpr); ok { + if call2, ok := bin.X.(*ast.CallExpr); ok && len(call2.Args) == 1 { + if isFieldSelector(call2.Args[0], "m", "Items") { + call2.Args[0] = &ast.StarExpr{X: &ast.Ident{Name: "m"}} + } + } + } + } + } + } + } + } + case *ast.IndexExpr: + if isFieldSelector(t.X, "m", "Items") { + t.X = &ast.Ident{Name: "m"} + return nil + } + case *ast.CallExpr: + changed := false + for i := range t.Args { + if isFieldSelector(t.Args[i], "m", "Items") { + t.Args[i] = &ast.Ident{Name: "m"} + changed = true + } + } + if changed { + return nil + } + } + return v +} + +func isFieldSelector(n ast.Expr, name, field string) bool { + s, ok := n.(*ast.SelectorExpr) + if !ok || s.Sel == nil || (field != "" && s.Sel.Name != field) { + return false + } + return isIdent(s.X, name) +} + +func isIdent(n ast.Expr, value string) bool { + ident, ok := n.(*ast.Ident) + return ok && ident.Name == value +} + +func receiver(f *ast.FuncDecl) (ident *ast.Ident, pointer bool, ok bool) { + if f.Recv == nil || len(f.Recv.List) != 1 { + return nil, false, false + } + switch t := f.Recv.List[0].Type.(type) { + case *ast.StarExpr: + identity, ok := t.X.(*ast.Ident) + if !ok { + return nil, false, false + } + return identity, true, true + case *ast.Ident: + return t, false, true + } + return nil, false, false +} + +// dropExistingTypeDeclarations removes any type declaration for which extractFn returns true. The function +// returns true if the entire declaration should be dropped. +func dropExistingTypeDeclarations(decl ast.Decl, extractFn ExtractFunc) bool { + if t, ok := decl.(*ast.GenDecl); ok { + if t.Tok != token.TYPE { + return false + } + specs := []ast.Spec{} + for _, s := range t.Specs { + if spec, ok := s.(*ast.TypeSpec); ok { + if extractFn(spec) { + continue + } + specs = append(specs, spec) + } + } + if len(specs) == 0 { + return true + } + t.Specs = specs + } + return false +} + +// dropEmptyImportDeclarations strips any generated but no-op imports from the generated code +// to prevent generation from being able to define side-effects. The function returns true +// if the entire declaration should be dropped. +func dropEmptyImportDeclarations(decl ast.Decl) bool { + if t, ok := decl.(*ast.GenDecl); ok { + if t.Tok != token.IMPORT { + return false + } + specs := []ast.Spec{} + for _, s := range t.Specs { + if spec, ok := s.(*ast.ImportSpec); ok { + if spec.Name != nil && spec.Name.Name == "_" { + continue + } + specs = append(specs, spec) + } + } + if len(specs) == 0 { + return true + } + t.Specs = specs + } + return false +} + +func RewriteTypesWithProtobufStructTags(name string, structTags map[string]map[string]string) error { + return rewriteFile(name, []byte{}, func(fset *token.FileSet, file *ast.File) error { + allErrs := []error{} + + // set any new struct tags + for _, d := range file.Decls { + if errs := updateStructTags(d, structTags, []string{"protobuf"}); len(errs) > 0 { + allErrs = append(allErrs, errs...) + } + } + + if len(allErrs) > 0 { + var s string + for _, err := range allErrs { + s += err.Error() + "\n" + } + return errors.New(s) + } + return nil + }) +} + +func getFieldName(expr ast.Expr, structname string) (name string, err error) { + for { + switch t := expr.(type) { + case *ast.Ident: + return t.Name, nil + case *ast.SelectorExpr: + return t.Sel.Name, nil + case *ast.StarExpr: + expr = t.X + default: + return "", fmt.Errorf("unable to get name for tag from struct %q, field %#v", structname, t) + } + } +} + +func updateStructTags(decl ast.Decl, structTags map[string]map[string]string, toCopy []string) []error { + var errs []error + t, ok := decl.(*ast.GenDecl) + if !ok { + return nil + } + if t.Tok != token.TYPE { + return nil + } + + for _, s := range t.Specs { + spec, ok := s.(*ast.TypeSpec) + if !ok { + continue + } + typeName := spec.Name.Name + fieldTags, ok := structTags[typeName] + if !ok { + continue + } + st, ok := spec.Type.(*ast.StructType) + if !ok { + continue + } + + for i := range st.Fields.List { + f := st.Fields.List[i] + var name string + var err error + if len(f.Names) == 0 { + name, err = getFieldName(f.Type, spec.Name.Name) + if err != nil { + errs = append(errs, err) + continue + } + } else { + name = f.Names[0].Name + } + value, ok := fieldTags[name] + if !ok { + continue + } + var tags customreflect.StructTags + if f.Tag != nil { + oldTags, err := customreflect.ParseStructTags(strings.Trim(f.Tag.Value, "`")) + if err != nil { + errs = append(errs, fmt.Errorf("unable to read struct tag from struct %q, field %q: %v", spec.Name.Name, name, err)) + continue + } + tags = oldTags + } + for _, name := range toCopy { + // don't overwrite existing tags + if tags.Has(name) { + continue + } + // append new tags + if v := reflect.StructTag(value).Get(name); len(v) > 0 { + tags = append(tags, customreflect.StructTag{Name: name, Value: v}) + } + } + if len(tags) == 0 { + continue + } + if f.Tag == nil { + f.Tag = &ast.BasicLit{} + } + f.Tag.Value = tags.String() + } + } + return errs +} diff --git a/code-generator/cmd/go-to-protobuf/protobuf/parser_test.go b/code-generator/cmd/go-to-protobuf/protobuf/parser_test.go new file mode 100644 index 000000000..db765a30c --- /dev/null +++ b/code-generator/cmd/go-to-protobuf/protobuf/parser_test.go @@ -0,0 +1,119 @@ +/* +Copyright 2020 The Kubernetes 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 protobuf + +import ( + "go/ast" + "testing" +) + +/* + struct fields in go AST: + + type Struct struct { + // fields with a direct field Name as + A X // regular fields + B *X // pointer fields + C // embedded type field + + // qualified embedded type fields use an in the AST + v1.TypeMeta // X=v1, Sel=TypeMeta + + // fields without a direct name, but + // a in the go-AST + *D // type field embedded as pointer + *v1.ListMeta // qualified type field embedded as pointer + // with pointing to + } +*/ + +func TestProtoParser(t *testing.T) { + ident := ast.NewIdent("FieldName") + tests := []struct { + expr ast.Expr + err bool + }{ + // valid struct field expressions + { + expr: ident, + err: false, + }, + { + expr: &ast.SelectorExpr{ + Sel: ident, + }, + err: false, + }, + { + expr: &ast.StarExpr{ + X: ident, + }, + err: false, + }, + { + expr: &ast.StarExpr{ + X: &ast.StarExpr{ + X: ident, + }, + }, + err: false, + }, + { + expr: &ast.StarExpr{ + X: &ast.SelectorExpr{ + Sel: ident, + }, + }, + err: false, + }, + + // something else should provide an error + { + expr: &ast.KeyValueExpr{ + Key: ident, + Colon: 0, + Value: ident, + }, + err: true, + }, + { + expr: &ast.StarExpr{ + X: &ast.KeyValueExpr{ + Key: ident, + Colon: 0, + Value: ident, + }, + }, + err: true, + }, + } + + for _, test := range tests { + actual, err := getFieldName(test.expr, "Struct") + if !test.err { + if err != nil { + t.Errorf("%s: unexpected error %s", test.expr, err) + } else if actual != ident.Name { + t.Errorf("%s: expected %s, got %s", test.expr, ident.Name, actual) + } + } else { + if err == nil { + t.Errorf("%s: expected error did not occur, got %s instead", test.expr, actual) + } + } + } +} diff --git a/code-generator/cmd/go-to-protobuf/protobuf/tags.go b/code-generator/cmd/go-to-protobuf/protobuf/tags.go new file mode 100644 index 000000000..44ca07d1a --- /dev/null +++ b/code-generator/cmd/go-to-protobuf/protobuf/tags.go @@ -0,0 +1,33 @@ +/* +Copyright 2016 The Kubernetes 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 protobuf + +import ( + "k8s.io/gengo/v2" + "k8s.io/klog/v2" +) + +// extractBoolTagOrDie gets the comment-tags for the key and asserts that, if +// it exists, the value is boolean. If the tag did not exist, it returns +// false. +func extractBoolTagOrDie(key string, lines []string) bool { + val, err := gengo.ExtractSingleBoolCommentTag("+", key, false, lines) + if err != nil { + klog.Fatal(err) + } + return val +} diff --git a/code-generator/cmd/go-to-protobuf/protoc-gen-gogo/main.go b/code-generator/cmd/go-to-protobuf/protoc-gen-gogo/main.go new file mode 100644 index 000000000..a08512bce --- /dev/null +++ b/code-generator/cmd/go-to-protobuf/protoc-gen-gogo/main.go @@ -0,0 +1,51 @@ +/* +Copyright 2015 The Kubernetes 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 defines the protoc-gen-gogo binary we use to generate our proto go files, +// as well as takes dependencies on the correct gogo/protobuf packages for godeps. +package main + +import ( + "strings" + + "github.com/gogo/protobuf/vanity/command" + + // dependencies that are required for our packages + _ "github.com/gogo/protobuf/gogoproto" + _ "github.com/gogo/protobuf/proto" + _ "github.com/gogo/protobuf/sortkeys" +) + +func main() { + // read input + request := command.Read() + + // if we're given paths as inputs, generate .pb.go files based on those paths + for _, file := range request.FileToGenerate { + if strings.Contains(file, "/") { + if request.Parameter != nil { + *request.Parameter += ",paths=source_relative" + } else { + param := "paths=source_relative" + request.Parameter = ¶m + } + break + } + } + + // generate + command.Write(command.Generate(request)) +} diff --git a/code-generator/cmd/informer-gen/args/args.go b/code-generator/cmd/informer-gen/args/args.go new file mode 100644 index 000000000..8052578c5 --- /dev/null +++ b/code-generator/cmd/informer-gen/args/args.go @@ -0,0 +1,82 @@ +/* +Copyright 2017 The Kubernetes 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" +) + +// Args is used by the gengo framework to pass args specific to this generator. +type Args struct { + OutputDir string // must be a directory path + OutputPkg string // must be a Go import-path + GoHeaderFile string + VersionedClientSetPackage string // must be a Go import-path + InternalClientSetPackage string // must be a Go import-path + ListersPackage string // must be a Go import-path + SingleDirectory bool + + // PluralExceptions define a list of pluralizer exceptions in Type:PluralType format. + // The default list is "Endpoints:Endpoints" + PluralExceptions []string +} + +// New returns default arguments for the generator. +func New() *Args { + return &Args{ + SingleDirectory: false, + } +} + +// AddFlags add the generator flags to the flag set. +func (args *Args) AddFlags(fs *pflag.FlagSet) { + fs.StringVar(&args.OutputDir, "output-dir", "", + "the base directory under which to generate results") + fs.StringVar(&args.OutputPkg, "output-pkg", args.OutputPkg, + "the Go import-path of the generated results") + fs.StringVar(&args.GoHeaderFile, "go-header-file", "", + "the path to a file containing boilerplate header text; the string \"YEAR\" will be replaced with the current 4-digit year") + fs.StringVar(&args.InternalClientSetPackage, "internal-clientset-package", args.InternalClientSetPackage, + "the Go import-path of the internal clientset to use") + fs.StringVar(&args.VersionedClientSetPackage, "versioned-clientset-package", args.VersionedClientSetPackage, + "the Go import-path of the versioned clientset to use") + fs.StringVar(&args.ListersPackage, "listers-package", args.ListersPackage, + "the Go import-path of the listers to use") + fs.BoolVar(&args.SingleDirectory, "single-directory", args.SingleDirectory, + "if true, omit the intermediate \"internalversion\" and \"externalversions\" subdirectories") + fs.StringSliceVar(&args.PluralExceptions, "plural-exceptions", args.PluralExceptions, + "list of comma separated plural exception definitions in Type:PluralizedType format") +} + +// Validate checks the given arguments. +func (args *Args) Validate() error { + if len(args.OutputDir) == 0 { + return fmt.Errorf("--output-dir must be specified") + } + if len(args.OutputPkg) == 0 { + return fmt.Errorf("--output-pkg must be specified") + } + if len(args.VersionedClientSetPackage) == 0 { + return fmt.Errorf("--versioned-clientset-package must be specified") + } + if len(args.ListersPackage) == 0 { + return fmt.Errorf("--listers-package must be specified") + } + return nil +} diff --git a/code-generator/cmd/informer-gen/generators/factory.go b/code-generator/cmd/informer-gen/generators/factory.go new file mode 100644 index 000000000..b27cfeb0a --- /dev/null +++ b/code-generator/cmd/informer-gen/generators/factory.go @@ -0,0 +1,341 @@ +/* +Copyright 2016 The Kubernetes 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" + "path" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + + "k8s.io/klog/v2" +) + +// factoryGenerator produces a file of listers for a given GroupVersion and +// type. +type factoryGenerator struct { + generator.GoGenerator + outputPackage string + imports namer.ImportTracker + groupVersions map[string]clientgentypes.GroupVersions + gvGoNames map[string]string + clientSetPackage string + internalInterfacesPackage string + filtered bool +} + +var _ generator.Generator = &factoryGenerator{} + +func (g *factoryGenerator) Filter(c *generator.Context, t *types.Type) bool { + 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).Infof("processing type %v", t) + + gvInterfaces := make(map[string]*types.Type) + gvNewFuncs := make(map[string]*types.Type) + for groupPkgName := range g.groupVersions { + gvInterfaces[groupPkgName] = c.Universe.Type(types.Name{Package: path.Join(g.outputPackage, groupPkgName), Name: "Interface"}) + gvNewFuncs[groupPkgName] = c.Universe.Function(types.Name{Package: path.Join(g.outputPackage, groupPkgName), Name: "New"}) + } + m := map[string]interface{}{ + "cacheSharedIndexInformer": c.Universe.Type(cacheSharedIndexInformer), + "cacheTransformFunc": c.Universe.Type(cacheTransformFunc), + "groupVersions": g.groupVersions, + "gvInterfaces": gvInterfaces, + "gvNewFuncs": gvNewFuncs, + "gvGoNames": g.gvGoNames, + "interfacesNewInformerFunc": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "NewInformerFunc"}), + "interfacesTweakListOptionsFunc": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "TweakListOptionsFunc"}), + "informerFactoryInterface": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "SharedInformerFactory"}), + "clientSetInterface": c.Universe.Type(types.Name{Package: g.clientSetPackage, Name: "Interface"}), + "reflectType": c.Universe.Type(reflectType), + "runtimeObject": c.Universe.Type(runtimeObject), + "schemaGroupVersionResource": c.Universe.Type(schemaGroupVersionResource), + "syncMutex": c.Universe.Type(syncMutex), + "timeDuration": c.Universe.Type(timeDuration), + "namespaceAll": c.Universe.Type(metav1NamespaceAll), + "object": c.Universe.Type(metav1Object), + } + + sw.Do(sharedInformerFactoryStruct, m) + sw.Do(sharedInformerFactoryInterface, m) + + return sw.Error() +} + +var sharedInformerFactoryStruct = ` +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client {{.clientSetInterface|raw}} + namespace string + tweakListOptions {{.interfacesTweakListOptionsFunc|raw}} + lock {{.syncMutex|raw}} + defaultResync {{.timeDuration|raw}} + customResync map[{{.reflectType|raw}}]{{.timeDuration|raw}} + transform {{.cacheTransformFunc|raw}} + + informers map[{{.reflectType|raw}}]{{.cacheSharedIndexInformer|raw}} + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[{{.reflectType|raw}}]bool + // wg tracks how many goroutines were started. + wg sync.WaitGroup + // shuttingDown is true when Shutdown has been called. It may still be running + // because it needs to wait for goroutines. + shuttingDown bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[{{.object|raw}}]{{.timeDuration|raw}}) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// WithTransform sets a transform on all informers. +func WithTransform(transform {{.cacheTransformFunc|raw}}) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.transform = transform + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client {{.clientSetInterface|raw}}, defaultResync {{.timeDuration|raw}}) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client {{.clientSetInterface|raw}}, defaultResync {{.timeDuration|raw}}, namespace string, tweakListOptions {{.interfacesTweakListOptionsFunc|raw}}) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client {{.clientSetInterface|raw}}, defaultResync {{.timeDuration|raw}}, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[{{.reflectType|raw}}]{{.cacheSharedIndexInformer|raw}}), + startedInformers: make(map[{{.reflectType|raw}}]bool), + customResync: make(map[{{.reflectType|raw}}]{{.timeDuration|raw}}), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + if f.shuttingDown { + return + } + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + f.wg.Add(1) + // We need a new variable in each loop iteration, + // otherwise the goroutine would use the loop variable + // and that keeps changing. + informer := informer + go func() { + defer f.wg.Done() + informer.Run(stopCh) + }() + f.startedInformers[informerType] = true + } + } +} + +func (f *sharedInformerFactory) Shutdown() { + f.lock.Lock() + f.shuttingDown = true + f.lock.Unlock() + + + // Will return immediately if there is nothing to wait for. + f.wg.Wait() +} + +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func()map[reflect.Type]cache.SharedIndexInformer{ + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj {{.runtimeObject|raw}}, newFunc {{.interfacesNewInformerFunc|raw}}) {{.cacheSharedIndexInformer|raw}} { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + informer.SetTransform(f.transform) + f.informers[informerType] = informer + + return informer +} +` + +var sharedInformerFactoryInterface = ` +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +// +// It is typically used like this: +// +// ctx, cancel := context.Background() +// defer cancel() +// factory := NewSharedInformerFactory(client, resyncPeriod) +// defer factory.WaitForStop() // Returns immediately if nothing was started. +// genericInformer := factory.ForResource(resource) +// typedInformer := factory.SomeAPIGroup().V1().SomeType() +// factory.Start(ctx.Done()) // Start processing these informers. +// synced := factory.WaitForCacheSync(ctx.Done()) +// for v, ok := range synced { +// if !ok { +// fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v) +// return +// } +// } +// +// // Creating informers can also be created after Start, but then +// // Start must be called again: +// anotherGenericInformer := factory.ForResource(resource) +// factory.Start(ctx.Done()) +type SharedInformerFactory interface { + {{.informerFactoryInterface|raw}} + + // Start initializes all requested informers. They are handled in goroutines + // which run until the stop channel gets closed. + // Warning: Start does not block. When run in a go-routine, it will race with a later WaitForCacheSync. + Start(stopCh <-chan struct{}) + + // Shutdown marks a factory as shutting down. At that point no new + // informers can be started anymore and Start will return without + // doing anything. + // + // In addition, Shutdown blocks until all goroutines have terminated. For that + // to happen, the close channel(s) that they were started with must be closed, + // either before Shutdown gets called or while it is waiting. + // + // Shutdown may be called multiple times, even concurrently. All such calls will + // block until all goroutines have terminated. + Shutdown() + + // WaitForCacheSync blocks until all started informers' caches were synced + // or the stop channel gets closed. + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + // ForResource gives generic access to a shared informer of the matching type. + ForResource(resource {{.schemaGroupVersionResource|raw}}) (GenericInformer, error) + + // InformerFor returns the SharedIndexInformer for obj using an internal + // client. + InformerFor(obj {{.runtimeObject|raw}}, newFunc {{.interfacesNewInformerFunc|raw}}) {{.cacheSharedIndexInformer|raw}} + + {{$gvInterfaces := .gvInterfaces}} + {{$gvGoNames := .gvGoNames}} + {{range $groupName, $group := .groupVersions}}{{index $gvGoNames $groupName}}() {{index $gvInterfaces $groupName|raw}} + {{end}} +} + +{{$gvNewFuncs := .gvNewFuncs}} +{{$gvGoNames := .gvGoNames}} +{{range $groupPkgName, $group := .groupVersions}} +func (f *sharedInformerFactory) {{index $gvGoNames $groupPkgName}}() {{index $gvInterfaces $groupPkgName|raw}} { + return {{index $gvNewFuncs $groupPkgName|raw}}(f, f.namespace, f.tweakListOptions) +} +{{end}} +` diff --git a/code-generator/cmd/informer-gen/generators/factoryinterface.go b/code-generator/cmd/informer-gen/generators/factoryinterface.go new file mode 100644 index 000000000..278f8ed91 --- /dev/null +++ b/code-generator/cmd/informer-gen/generators/factoryinterface.go @@ -0,0 +1,90 @@ +/* +Copyright 2016 The Kubernetes 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/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + + "k8s.io/klog/v2" +) + +// factoryInterfaceGenerator produces a file of interfaces used to break a dependency cycle for +// informer registration +type factoryInterfaceGenerator struct { + generator.GoGenerator + outputPackage string + imports namer.ImportTracker + clientSetPackage string + filtered bool +} + +var _ generator.Generator = &factoryInterfaceGenerator{} + +func (g *factoryInterfaceGenerator) Filter(c *generator.Context, t *types.Type) bool { + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *factoryInterfaceGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *factoryInterfaceGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *factoryInterfaceGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + klog.V(5).Infof("processing type %v", t) + + m := map[string]interface{}{ + "cacheSharedIndexInformer": c.Universe.Type(cacheSharedIndexInformer), + "clientSetPackage": c.Universe.Type(types.Name{Package: g.clientSetPackage, Name: "Interface"}), + "runtimeObject": c.Universe.Type(runtimeObject), + "timeDuration": c.Universe.Type(timeDuration), + "v1ListOptions": c.Universe.Type(v1ListOptions), + } + + sw.Do(externalSharedInformerFactoryInterface, m) + + return sw.Error() +} + +var externalSharedInformerFactoryInterface = ` +// NewInformerFunc takes {{.clientSetPackage|raw}} and {{.timeDuration|raw}} to return a SharedIndexInformer. +type NewInformerFunc func({{.clientSetPackage|raw}}, {{.timeDuration|raw}}) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj {{.runtimeObject|raw}}, newFunc NewInformerFunc) {{.cacheSharedIndexInformer|raw}} +} + +// TweakListOptionsFunc is a function that transforms a {{.v1ListOptions|raw}}. +type TweakListOptionsFunc func(*{{.v1ListOptions|raw}}) +` diff --git a/code-generator/cmd/informer-gen/generators/generic.go b/code-generator/cmd/informer-gen/generators/generic.go new file mode 100644 index 000000000..e863b1d2f --- /dev/null +++ b/code-generator/cmd/informer-gen/generators/generic.go @@ -0,0 +1,184 @@ +/* +Copyright 2016 The Kubernetes 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" + "sort" + "strings" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + codegennamer "k8s.io/code-generator/pkg/namer" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" +) + +// genericGenerator generates the generic informer. +type genericGenerator struct { + generator.GoGenerator + outputPackage string + imports namer.ImportTracker + groupVersions map[string]clientgentypes.GroupVersions + groupGoNames map[string]string + pluralExceptions map[string]string + typesForGroupVersion map[clientgentypes.GroupVersion][]*types.Type + filtered bool +} + +var _ generator.Generator = &genericGenerator{} + +func (g *genericGenerator) Filter(c *generator.Context, t *types.Type) bool { + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *genericGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + "allLowercasePlural": namer.NewAllLowercasePluralNamer(g.pluralExceptions), + "publicPlural": namer.NewPublicPluralNamer(g.pluralExceptions), + "resource": codegennamer.NewTagOverrideNamer("resourceName", namer.NewAllLowercasePluralNamer(g.pluralExceptions)), + } +} + +func (g *genericGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +type group struct { + GroupGoName string + Name string + Versions []*version +} + +type groupSort []group + +func (g groupSort) Len() int { return len(g) } +func (g groupSort) Less(i, j int) bool { + return strings.ToLower(g[i].Name) < strings.ToLower(g[j].Name) +} +func (g groupSort) Swap(i, j int) { g[i], g[j] = g[j], g[i] } + +type version struct { + Name string + GoName string + Resources []*types.Type +} + +type versionSort []*version + +func (v versionSort) Len() int { return len(v) } +func (v versionSort) Less(i, j int) bool { + return strings.ToLower(v[i].Name) < strings.ToLower(v[j].Name) +} +func (v versionSort) Swap(i, j int) { v[i], v[j] = v[j], v[i] } + +func (g *genericGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "{{", "}}") + + groups := []group{} + schemeGVs := make(map[*version]*types.Type) + + orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)} + for groupPackageName, groupVersions := range g.groupVersions { + group := group{ + GroupGoName: g.groupGoNames[groupPackageName], + Name: groupVersions.Group.NonEmpty(), + Versions: []*version{}, + } + for _, v := range groupVersions.Versions { + gv := clientgentypes.GroupVersion{Group: groupVersions.Group, Version: v.Version} + version := &version{ + Name: v.Version.NonEmpty(), + GoName: namer.IC(v.Version.NonEmpty()), + Resources: orderer.OrderTypes(g.typesForGroupVersion[gv]), + } + func() { + schemeGVs[version] = c.Universe.Variable(types.Name{Package: g.typesForGroupVersion[gv][0].Name.Package, Name: "SchemeGroupVersion"}) + }() + group.Versions = append(group.Versions, version) + } + sort.Sort(versionSort(group.Versions)) + groups = append(groups, group) + } + sort.Sort(groupSort(groups)) + + m := map[string]interface{}{ + "cacheGenericLister": c.Universe.Type(cacheGenericLister), + "cacheNewGenericLister": c.Universe.Function(cacheNewGenericLister), + "cacheSharedIndexInformer": c.Universe.Type(cacheSharedIndexInformer), + "fmtErrorf": c.Universe.Type(fmtErrorfFunc), + "groups": groups, + "schemeGVs": schemeGVs, + "schemaGroupResource": c.Universe.Type(schemaGroupResource), + "schemaGroupVersionResource": c.Universe.Type(schemaGroupVersionResource), + } + + sw.Do(genericInformer, m) + sw.Do(forResource, m) + + return sw.Error() +} + +var genericInformer = ` +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() {{.cacheSharedIndexInformer|raw}} + Lister() {{.cacheGenericLister|raw}} +} + +type genericInformer struct { + informer {{.cacheSharedIndexInformer|raw}} + resource {{.schemaGroupResource|raw}} +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() {{.cacheSharedIndexInformer|raw}} { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() {{.cacheGenericLister|raw}} { + return {{.cacheNewGenericLister|raw}}(f.Informer().GetIndexer(), f.resource) +} +` + +var forResource = ` +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource {{.schemaGroupVersionResource|raw}}) (GenericInformer, error) { + switch resource { + {{range $group := .groups -}}{{$GroupGoName := .GroupGoName -}} + {{range $version := .Versions -}} + // Group={{$group.Name}}, Version={{.Name}} + {{range .Resources -}} + case {{index $.schemeGVs $version|raw}}.WithResource("{{.|resource}}"): + return &genericInformer{resource: resource.GroupResource(), informer: f.{{$GroupGoName}}().{{$version.GoName}}().{{.|publicPlural}}().Informer()}, nil + {{end}} + {{end}} + {{end -}} + } + + return nil, {{.fmtErrorf|raw}}("no informer found for %v", resource) +} +` diff --git a/code-generator/cmd/informer-gen/generators/groupinterface.go b/code-generator/cmd/informer-gen/generators/groupinterface.go new file mode 100644 index 000000000..5342e25d9 --- /dev/null +++ b/code-generator/cmd/informer-gen/generators/groupinterface.go @@ -0,0 +1,118 @@ +/* +Copyright 2016 The Kubernetes 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" + "path" + "strings" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" +) + +// groupInterfaceGenerator generates the per-group interface file. +type groupInterfaceGenerator struct { + generator.GoGenerator + outputPackage string + imports namer.ImportTracker + groupVersions clientgentypes.GroupVersions + filtered bool + internalInterfacesPackage string +} + +var _ generator.Generator = &groupInterfaceGenerator{} + +func (g *groupInterfaceGenerator) Filter(c *generator.Context, t *types.Type) bool { + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *groupInterfaceGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *groupInterfaceGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +type versionData struct { + Name string + Interface *types.Type + New *types.Type +} + +func (g *groupInterfaceGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + + versions := make([]versionData, 0, len(g.groupVersions.Versions)) + for _, version := range g.groupVersions.Versions { + gv := clientgentypes.GroupVersion{Group: g.groupVersions.Group, Version: version.Version} + versionPackage := path.Join(g.outputPackage, strings.ToLower(gv.Version.NonEmpty())) + iface := c.Universe.Type(types.Name{Package: versionPackage, Name: "Interface"}) + versions = append(versions, versionData{ + Name: namer.IC(version.Version.NonEmpty()), + Interface: iface, + New: c.Universe.Function(types.Name{Package: versionPackage, Name: "New"}), + }) + } + m := map[string]interface{}{ + "interfacesTweakListOptionsFunc": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "TweakListOptionsFunc"}), + "interfacesSharedInformerFactory": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "SharedInformerFactory"}), + "versions": versions, + } + + sw.Do(groupTemplate, m) + + return sw.Error() +} + +var groupTemplate = ` +// Interface provides access to each of this group's versions. +type Interface interface { + $range .versions -$ + // $.Name$ provides access to shared informers for resources in $.Name$. + $.Name$() $.Interface|raw$ + $end$ +} + +type group struct { + factory $.interfacesSharedInformerFactory|raw$ + namespace string + tweakListOptions $.interfacesTweakListOptionsFunc|raw$ +} + +// New returns a new Interface. +func New(f $.interfacesSharedInformerFactory|raw$, namespace string, tweakListOptions $.interfacesTweakListOptionsFunc|raw$) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +$range .versions$ +// $.Name$ returns a new $.Interface|raw$. +func (g *group) $.Name$() $.Interface|raw$ { + return $.New|raw$(g.factory, g.namespace, g.tweakListOptions) +} +$end$ +` diff --git a/code-generator/cmd/informer-gen/generators/informer.go b/code-generator/cmd/informer-gen/generators/informer.go new file mode 100644 index 000000000..4034695dd --- /dev/null +++ b/code-generator/cmd/informer-gen/generators/informer.go @@ -0,0 +1,187 @@ +/* +Copyright 2016 The Kubernetes 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 ( + "fmt" + "io" + "strings" + + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + + "k8s.io/code-generator/cmd/client-gen/generators/util" + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + + "k8s.io/klog/v2" +) + +// informerGenerator produces a file of listers for a given GroupVersion and +// type. +type informerGenerator struct { + generator.GoGenerator + outputPackage string + groupPkgName string + groupVersion clientgentypes.GroupVersion + groupGoName string + typeToGenerate *types.Type + imports namer.ImportTracker + clientSetPackage string + listersPackage string + internalInterfacesPackage string +} + +var _ generator.Generator = &informerGenerator{} + +func (g *informerGenerator) Filter(c *generator.Context, t *types.Type) bool { + return t == g.typeToGenerate +} + +func (g *informerGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *informerGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *informerGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + + klog.V(5).Infof("processing type %v", t) + + listerPackage := fmt.Sprintf("%s/%s/%s", g.listersPackage, g.groupPkgName, strings.ToLower(g.groupVersion.Version.NonEmpty())) + clientSetInterface := c.Universe.Type(types.Name{Package: g.clientSetPackage, Name: "Interface"}) + informerFor := "InformerFor" + + tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if err != nil { + return err + } + + m := map[string]interface{}{ + "apiScheme": c.Universe.Type(apiScheme), + "cacheIndexers": c.Universe.Type(cacheIndexers), + "cacheListWatch": c.Universe.Type(cacheListWatch), + "cacheMetaNamespaceIndexFunc": c.Universe.Function(cacheMetaNamespaceIndexFunc), + "cacheNamespaceIndex": c.Universe.Variable(cacheNamespaceIndex), + "cacheNewSharedIndexInformer": c.Universe.Function(cacheNewSharedIndexInformer), + "cacheSharedIndexInformer": c.Universe.Type(cacheSharedIndexInformer), + "clientSetInterface": clientSetInterface, + "contextTODO": c.Universe.Type(contextTODOFunc), + "group": namer.IC(g.groupGoName), + "informerFor": informerFor, + "interfacesTweakListOptionsFunc": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "TweakListOptionsFunc"}), + "interfacesSharedInformerFactory": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "SharedInformerFactory"}), + "listOptions": c.Universe.Type(listOptions), + "lister": c.Universe.Type(types.Name{Package: listerPackage, Name: t.Name.Name + "Lister"}), + "namespaceAll": c.Universe.Type(metav1NamespaceAll), + "namespaced": !tags.NonNamespaced, + "newLister": c.Universe.Function(types.Name{Package: listerPackage, Name: "New" + t.Name.Name + "Lister"}), + "runtimeObject": c.Universe.Type(runtimeObject), + "timeDuration": c.Universe.Type(timeDuration), + "type": t, + "v1ListOptions": c.Universe.Type(v1ListOptions), + "version": namer.IC(g.groupVersion.Version.String()), + "watchInterface": c.Universe.Type(watchInterface), + } + + sw.Do(typeInformerInterface, m) + sw.Do(typeInformerStruct, m) + sw.Do(typeInformerPublicConstructor, m) + sw.Do(typeFilteredInformerPublicConstructor, m) + sw.Do(typeInformerConstructor, m) + sw.Do(typeInformerInformer, m) + sw.Do(typeInformerLister, m) + + return sw.Error() +} + +var typeInformerInterface = ` +// $.type|public$Informer provides access to a shared informer and lister for +// $.type|publicPlural$. +type $.type|public$Informer interface { + Informer() $.cacheSharedIndexInformer|raw$ + Lister() $.lister|raw$ +} +` + +var typeInformerStruct = ` +type $.type|private$Informer struct { + factory $.interfacesSharedInformerFactory|raw$ + tweakListOptions $.interfacesTweakListOptionsFunc|raw$ + $if .namespaced$namespace string$end$ +} +` + +var typeInformerPublicConstructor = ` +// New$.type|public$Informer constructs a new informer for $.type|public$ type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func New$.type|public$Informer(client $.clientSetInterface|raw$$if .namespaced$, namespace string$end$, resyncPeriod $.timeDuration|raw$, indexers $.cacheIndexers|raw$) $.cacheSharedIndexInformer|raw$ { + return NewFiltered$.type|public$Informer(client$if .namespaced$, namespace$end$, resyncPeriod, indexers, nil) +} +` + +var typeFilteredInformerPublicConstructor = ` +// NewFiltered$.type|public$Informer constructs a new informer for $.type|public$ type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFiltered$.type|public$Informer(client $.clientSetInterface|raw$$if .namespaced$, namespace string$end$, resyncPeriod $.timeDuration|raw$, indexers $.cacheIndexers|raw$, tweakListOptions $.interfacesTweakListOptionsFunc|raw$) $.cacheSharedIndexInformer|raw$ { + return $.cacheNewSharedIndexInformer|raw$( + &$.cacheListWatch|raw${ + ListFunc: func(options $.v1ListOptions|raw$) ($.runtimeObject|raw$, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.$.group$$.version$().$.type|publicPlural$($if .namespaced$namespace$end$).List($.contextTODO|raw$(), options) + }, + WatchFunc: func(options $.v1ListOptions|raw$) ($.watchInterface|raw$, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.$.group$$.version$().$.type|publicPlural$($if .namespaced$namespace$end$).Watch($.contextTODO|raw$(), options) + }, + }, + &$.type|raw${}, + resyncPeriod, + indexers, + ) +} +` + +var typeInformerConstructor = ` +func (f *$.type|private$Informer) defaultInformer(client $.clientSetInterface|raw$, resyncPeriod $.timeDuration|raw$) $.cacheSharedIndexInformer|raw$ { + return NewFiltered$.type|public$Informer(client$if .namespaced$, f.namespace$end$, resyncPeriod, $.cacheIndexers|raw${$.cacheNamespaceIndex|raw$: $.cacheMetaNamespaceIndexFunc|raw$}, f.tweakListOptions) +} +` + +var typeInformerInformer = ` +func (f *$.type|private$Informer) Informer() $.cacheSharedIndexInformer|raw$ { + return f.factory.$.informerFor$(&$.type|raw${}, f.defaultInformer) +} +` + +var typeInformerLister = ` +func (f *$.type|private$Informer) Lister() $.lister|raw$ { + return $.newLister|raw$(f.Informer().GetIndexer()) +} +` diff --git a/code-generator/cmd/informer-gen/generators/targets.go b/code-generator/cmd/informer-gen/generators/targets.go new file mode 100644 index 000000000..2e886d4e0 --- /dev/null +++ b/code-generator/cmd/informer-gen/generators/targets.go @@ -0,0 +1,373 @@ +/* +Copyright 2016 The Kubernetes 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 ( + "fmt" + "path" + "path/filepath" + "strings" + + "k8s.io/code-generator/cmd/client-gen/generators/util" + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/code-generator/cmd/informer-gen/args" + genutil "k8s.io/code-generator/pkg/util" + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + "k8s.io/klog/v2" +) + +// NameSystems returns the name system used by the generators in this package. +func NameSystems(pluralExceptions map[string]string) namer.NameSystems { + return namer.NameSystems{ + "public": namer.NewPublicNamer(0), + "private": namer.NewPrivateNamer(0), + "raw": namer.NewRawNamer("", nil), + "publicPlural": namer.NewPublicPluralNamer(pluralExceptions), + "allLowercasePlural": namer.NewAllLowercasePluralNamer(pluralExceptions), + "lowercaseSingular": &lowercaseSingularNamer{}, + } +} + +// 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) +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +// objectMetaForPackage returns the type of ObjectMeta used by package p. +func objectMetaForPackage(p *types.Package) (*types.Type, bool, error) { + generatingForPackage := false + for _, t := range p.Types { + if !util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)).GenerateClient { + continue + } + generatingForPackage = true + for _, member := range t.Members { + if member.Name == "ObjectMeta" { + return member.Type, isInternal(member), nil + } + } + } + if generatingForPackage { + return nil, false, fmt.Errorf("unable to find ObjectMeta for any types in package %s", p.Path) + } + return nil, false, nil +} + +// isInternal returns true if the tags for a member do not contain a json tag +func isInternal(m types.Member) bool { + return !strings.Contains(m.Tags, "json") +} + +const subdirForInternalInterfaces = "internalinterfaces" + +// GetTargets makes the client target definition. +func GetTargets(context *generator.Context, args *args.Args) []generator.Target { + boilerplate, err := gengo.GoBoilerplate(args.GoHeaderFile, "", gengo.StdGeneratedBy) + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + internalVersionOutputDir := args.OutputDir + internalVersionOutputPkg := args.OutputPkg + externalVersionOutputDir := args.OutputDir + externalVersionOutputPkg := args.OutputPkg + if !args.SingleDirectory { + internalVersionOutputDir = filepath.Join(internalVersionOutputDir, "internalversion") + internalVersionOutputPkg = path.Join(internalVersionOutputPkg, "internalversion") + externalVersionOutputDir = filepath.Join(externalVersionOutputDir, "externalversions") + externalVersionOutputPkg = path.Join(externalVersionOutputPkg, "externalversions") + } + + var targetList []generator.Target + typesForGroupVersion := make(map[clientgentypes.GroupVersion][]*types.Type) + + externalGroupVersions := make(map[string]clientgentypes.GroupVersions) + internalGroupVersions := make(map[string]clientgentypes.GroupVersions) + groupGoNames := make(map[string]string) + for _, inputPkg := range context.Inputs { + p := context.Universe.Package(inputPkg) + + objectMeta, internal, err := objectMetaForPackage(p) + if err != nil { + klog.Fatal(err) + } + if objectMeta == nil { + // no types in this package had genclient + continue + } + + var gv clientgentypes.GroupVersion + var targetGroupVersions map[string]clientgentypes.GroupVersions + + if internal { + lastSlash := strings.LastIndex(p.Path, "/") + if lastSlash == -1 { + klog.Fatalf("error constructing internal group version for package %q", p.Path) + } + gv.Group = clientgentypes.Group(p.Path[lastSlash+1:]) + targetGroupVersions = internalGroupVersions + } else { + parts := strings.Split(p.Path, "/") + gv.Group = clientgentypes.Group(parts[len(parts)-2]) + gv.Version = clientgentypes.Version(parts[len(parts)-1]) + targetGroupVersions = externalGroupVersions + } + 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 := gengo.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.Split(gv.Group.NonEmpty(), ".")[0]) + if override := gengo.ExtractCommentTags("+", p.Comments)["groupGoName"]; override != nil { + groupGoNames[groupPackageName] = namer.IC(override[0]) + } + + var typesToGenerate []*types.Type + for _, t := range p.Types { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if !tags.GenerateClient || tags.NoVerbs || !tags.HasVerb("list") || !tags.HasVerb("watch") { + continue + } + + typesToGenerate = append(typesToGenerate, t) + + if _, ok := typesForGroupVersion[gv]; !ok { + typesForGroupVersion[gv] = []*types.Type{} + } + typesForGroupVersion[gv] = append(typesForGroupVersion[gv], t) + } + if len(typesToGenerate) == 0 { + continue + } + + 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 + + orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)} + typesToGenerate = orderer.OrderTypes(typesToGenerate) + + if internal { + targetList = append(targetList, + versionTarget( + internalVersionOutputDir, internalVersionOutputPkg, + groupPackageName, gv, groupGoNames[groupPackageName], + boilerplate, typesToGenerate, + args.InternalClientSetPackage, args.ListersPackage)) + } else { + targetList = append(targetList, + versionTarget( + externalVersionOutputDir, externalVersionOutputPkg, + groupPackageName, gv, groupGoNames[groupPackageName], + boilerplate, typesToGenerate, + args.VersionedClientSetPackage, args.ListersPackage)) + } + } + + if len(externalGroupVersions) != 0 { + targetList = append(targetList, + factoryInterfaceTarget( + externalVersionOutputDir, externalVersionOutputPkg, + boilerplate, args.VersionedClientSetPackage)) + targetList = append(targetList, + factoryTarget( + externalVersionOutputDir, externalVersionOutputPkg, + boilerplate, groupGoNames, genutil.PluralExceptionListToMapOrDie(args.PluralExceptions), + externalGroupVersions, args.VersionedClientSetPackage, typesForGroupVersion)) + for _, gvs := range externalGroupVersions { + targetList = append(targetList, + groupTarget(externalVersionOutputDir, externalVersionOutputPkg, gvs, boilerplate)) + } + } + + if len(internalGroupVersions) != 0 { + targetList = append(targetList, + factoryInterfaceTarget(internalVersionOutputDir, internalVersionOutputPkg, boilerplate, args.InternalClientSetPackage)) + targetList = append(targetList, + factoryTarget( + internalVersionOutputDir, internalVersionOutputPkg, + boilerplate, groupGoNames, genutil.PluralExceptionListToMapOrDie(args.PluralExceptions), + internalGroupVersions, args.InternalClientSetPackage, typesForGroupVersion)) + for _, gvs := range internalGroupVersions { + targetList = append(targetList, + groupTarget(internalVersionOutputDir, internalVersionOutputPkg, gvs, boilerplate)) + } + } + + return targetList +} + +func factoryTarget(outputDirBase, outputPkgBase string, boilerplate []byte, groupGoNames, pluralExceptions map[string]string, groupVersions map[string]clientgentypes.GroupVersions, clientSetPackage string, + typesForGroupVersion map[clientgentypes.GroupVersion][]*types.Type) generator.Target { + return &generator.SimpleTarget{ + PkgName: path.Base(outputDirBase), + PkgPath: outputPkgBase, + PkgDir: outputDirBase, + HeaderComment: boilerplate, + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = append(generators, &factoryGenerator{ + GoGenerator: generator.GoGenerator{ + OutputFilename: "factory.go", + }, + outputPackage: outputPkgBase, + imports: generator.NewImportTrackerForPackage(outputPkgBase), + groupVersions: groupVersions, + clientSetPackage: clientSetPackage, + internalInterfacesPackage: path.Join(outputPkgBase, subdirForInternalInterfaces), + gvGoNames: groupGoNames, + }) + + generators = append(generators, &genericGenerator{ + GoGenerator: generator.GoGenerator{ + OutputFilename: "generic.go", + }, + outputPackage: outputPkgBase, + imports: generator.NewImportTrackerForPackage(outputPkgBase), + groupVersions: groupVersions, + pluralExceptions: pluralExceptions, + typesForGroupVersion: typesForGroupVersion, + groupGoNames: groupGoNames, + }) + + return generators + }, + } +} + +func factoryInterfaceTarget(outputDirBase, outputPkgBase string, boilerplate []byte, clientSetPackage string) generator.Target { + outputDir := filepath.Join(outputDirBase, subdirForInternalInterfaces) + outputPkg := path.Join(outputPkgBase, subdirForInternalInterfaces) + + return &generator.SimpleTarget{ + PkgName: path.Base(outputDir), + PkgPath: outputPkg, + PkgDir: outputDir, + HeaderComment: boilerplate, + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = append(generators, &factoryInterfaceGenerator{ + GoGenerator: generator.GoGenerator{ + OutputFilename: "factory_interfaces.go", + }, + outputPackage: outputPkg, + imports: generator.NewImportTrackerForPackage(outputPkg), + clientSetPackage: clientSetPackage, + }) + + return generators + }, + } +} + +func groupTarget(outputDirBase, outputPackageBase string, groupVersions clientgentypes.GroupVersions, boilerplate []byte) generator.Target { + outputDir := filepath.Join(outputDirBase, groupVersions.PackageName) + outputPkg := path.Join(outputPackageBase, groupVersions.PackageName) + groupPkgName := strings.Split(string(groupVersions.PackageName), ".")[0] + + return &generator.SimpleTarget{ + PkgName: groupPkgName, + PkgPath: outputPkg, + PkgDir: outputDir, + HeaderComment: boilerplate, + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = append(generators, &groupInterfaceGenerator{ + GoGenerator: generator.GoGenerator{ + OutputFilename: "interface.go", + }, + outputPackage: outputPkg, + groupVersions: groupVersions, + imports: generator.NewImportTrackerForPackage(outputPkg), + internalInterfacesPackage: path.Join(outputPackageBase, subdirForInternalInterfaces), + }) + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.GenerateClient && tags.HasVerb("list") && tags.HasVerb("watch") + }, + } +} + +func versionTarget(outputDirBase, outputPkgBase string, groupPkgName string, gv clientgentypes.GroupVersion, groupGoName string, boilerplate []byte, typesToGenerate []*types.Type, clientSetPackage, listersPackage string) generator.Target { + subdir := []string{groupPkgName, strings.ToLower(gv.Version.NonEmpty())} + outputDir := filepath.Join(outputDirBase, filepath.Join(subdir...)) + outputPkg := path.Join(outputPkgBase, path.Join(subdir...)) + + return &generator.SimpleTarget{ + PkgName: strings.ToLower(gv.Version.NonEmpty()), + PkgPath: outputPkg, + PkgDir: outputDir, + HeaderComment: boilerplate, + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = append(generators, &versionInterfaceGenerator{ + GoGenerator: generator.GoGenerator{ + OutputFilename: "interface.go", + }, + outputPackage: outputPkg, + imports: generator.NewImportTrackerForPackage(outputPkg), + types: typesToGenerate, + internalInterfacesPackage: path.Join(outputPkgBase, subdirForInternalInterfaces), + }) + + for _, t := range typesToGenerate { + generators = append(generators, &informerGenerator{ + GoGenerator: generator.GoGenerator{ + OutputFilename: strings.ToLower(t.Name.Name) + ".go", + }, + outputPackage: outputPkg, + groupPkgName: groupPkgName, + groupVersion: gv, + groupGoName: groupGoName, + typeToGenerate: t, + imports: generator.NewImportTrackerForPackage(outputPkg), + clientSetPackage: clientSetPackage, + listersPackage: listersPackage, + internalInterfacesPackage: path.Join(outputPkgBase, subdirForInternalInterfaces), + }) + } + return generators + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.GenerateClient && tags.HasVerb("list") && tags.HasVerb("watch") + }, + } +} diff --git a/code-generator/cmd/informer-gen/generators/types.go b/code-generator/cmd/informer-gen/generators/types.go new file mode 100644 index 000000000..b717adfd3 --- /dev/null +++ b/code-generator/cmd/informer-gen/generators/types.go @@ -0,0 +1,45 @@ +/* +Copyright 2016 The Kubernetes 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 "k8s.io/gengo/v2/types" + +var ( + apiScheme = types.Name{Package: "k8s.io/kubernetes/pkg/api/legacyscheme", Name: "Scheme"} + cacheGenericLister = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "GenericLister"} + cacheIndexers = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "Indexers"} + cacheListWatch = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "ListWatch"} + cacheMetaNamespaceIndexFunc = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "MetaNamespaceIndexFunc"} + cacheNamespaceIndex = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "NamespaceIndex"} + cacheNewGenericLister = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "NewGenericLister"} + cacheNewSharedIndexInformer = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "NewSharedIndexInformer"} + cacheSharedIndexInformer = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "SharedIndexInformer"} + cacheTransformFunc = types.Name{Package: "k8s.io/client-go/tools/cache", Name: "TransformFunc"} + contextTODOFunc = types.Name{Package: "context", Name: "TODO"} + fmtErrorfFunc = types.Name{Package: "fmt", Name: "Errorf"} + listOptions = types.Name{Package: "k8s.io/kubernetes/pkg/apis/core", Name: "ListOptions"} + reflectType = types.Name{Package: "reflect", Name: "Type"} + runtimeObject = types.Name{Package: "k8s.io/apimachinery/pkg/runtime", Name: "Object"} + schemaGroupResource = types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupResource"} + schemaGroupVersionResource = types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersionResource"} + syncMutex = types.Name{Package: "sync", Name: "Mutex"} + timeDuration = types.Name{Package: "time", Name: "Duration"} + v1ListOptions = types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "ListOptions"} + metav1NamespaceAll = types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "NamespaceAll"} + metav1Object = types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "Object"} + watchInterface = types.Name{Package: "k8s.io/apimachinery/pkg/watch", Name: "Interface"} +) diff --git a/code-generator/cmd/informer-gen/generators/versioninterface.go b/code-generator/cmd/informer-gen/generators/versioninterface.go new file mode 100644 index 000000000..5f9a0c218 --- /dev/null +++ b/code-generator/cmd/informer-gen/generators/versioninterface.go @@ -0,0 +1,109 @@ +/* +Copyright 2016 The Kubernetes 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/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + + "k8s.io/code-generator/cmd/client-gen/generators/util" +) + +// versionInterfaceGenerator generates the per-version interface file. +type versionInterfaceGenerator struct { + generator.GoGenerator + outputPackage string + imports namer.ImportTracker + types []*types.Type + filtered bool + internalInterfacesPackage string +} + +var _ generator.Generator = &versionInterfaceGenerator{} + +func (g *versionInterfaceGenerator) Filter(c *generator.Context, t *types.Type) bool { + if !g.filtered { + g.filtered = true + return true + } + return false +} + +func (g *versionInterfaceGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *versionInterfaceGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *versionInterfaceGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + + m := map[string]interface{}{ + "interfacesTweakListOptionsFunc": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "TweakListOptionsFunc"}), + "interfacesSharedInformerFactory": c.Universe.Type(types.Name{Package: g.internalInterfacesPackage, Name: "SharedInformerFactory"}), + "types": g.types, + } + + sw.Do(versionTemplate, m) + for _, typeDef := range g.types { + tags, err := util.ParseClientGenTags(append(typeDef.SecondClosestCommentLines, typeDef.CommentLines...)) + if err != nil { + return err + } + m["namespaced"] = !tags.NonNamespaced + m["type"] = typeDef + sw.Do(versionFuncTemplate, m) + } + + return sw.Error() +} + +var versionTemplate = ` +// Interface provides access to all the informers in this group version. +type Interface interface { + $range .types -$ + // $.|publicPlural$ returns a $.|public$Informer. + $.|publicPlural$() $.|public$Informer + $end$ +} + +type version struct { + factory $.interfacesSharedInformerFactory|raw$ + namespace string + tweakListOptions $.interfacesTweakListOptionsFunc|raw$ +} + +// New returns a new Interface. +func New(f $.interfacesSharedInformerFactory|raw$, namespace string, tweakListOptions $.interfacesTweakListOptionsFunc|raw$) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} +` + +var versionFuncTemplate = ` +// $.type|publicPlural$ returns a $.type|public$Informer. +func (v *version) $.type|publicPlural$() $.type|public$Informer { + return &$.type|private$Informer{factory: v.factory$if .namespaced$, namespace: v.namespace$end$, tweakListOptions: v.tweakListOptions} +} +` diff --git a/code-generator/cmd/informer-gen/main.go b/code-generator/cmd/informer-gen/main.go new file mode 100644 index 000000000..b0fc48517 --- /dev/null +++ b/code-generator/cmd/informer-gen/main.go @@ -0,0 +1,59 @@ +/* +Copyright 2016 The Kubernetes 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" + + "github.com/spf13/pflag" + "k8s.io/code-generator/cmd/informer-gen/args" + "k8s.io/code-generator/cmd/informer-gen/generators" + "k8s.io/code-generator/pkg/util" + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/klog/v2" +) + +func main() { + klog.InitFlags(nil) + args := args.New() + + args.AddFlags(pflag.CommandLine) + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + if err := args.Validate(); err != nil { + klog.Fatalf("Error: %v", err) + } + + myTargets := func(context *generator.Context) []generator.Target { + return generators.GetTargets(context, args) + } + + // Run it. + if err := gengo.Execute( + generators.NameSystems(util.PluralExceptionListToMapOrDie(args.PluralExceptions)), + generators.DefaultNameSystem(), + myTargets, + gengo.StdBuildTag, + pflag.Args(), + ); err != nil { + klog.Fatalf("Error: %v", err) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/code-generator/cmd/lister-gen/args/args.go b/code-generator/cmd/lister-gen/args/args.go new file mode 100644 index 000000000..e6b9e00ab --- /dev/null +++ b/code-generator/cmd/lister-gen/args/args.go @@ -0,0 +1,62 @@ +/* +Copyright 2017 The Kubernetes 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" +) + +// Args is used by the gengo framework to pass args specific to this generator. +type Args struct { + OutputDir string // must be a directory path + OutputPkg string // must be a Go import-path + GoHeaderFile string + + // PluralExceptions specify list of exceptions used when pluralizing certain types. + // For example 'Endpoints:Endpoints', otherwise the pluralizer will generate 'Endpointes'. + PluralExceptions []string +} + +// New returns default arguments for the generator. +func New() *Args { + return &Args{} +} + +// AddFlags add the generator flags to the flag set. +func (args *Args) AddFlags(fs *pflag.FlagSet) { + fs.StringVar(&args.OutputDir, "output-dir", "", + "the base directory under which to generate results") + fs.StringVar(&args.OutputPkg, "output-pkg", "", + "the base Go import-path under which to generate results") + fs.StringSliceVar(&args.PluralExceptions, "plural-exceptions", args.PluralExceptions, + "list of comma separated plural exception definitions in Type:PluralizedType format") + fs.StringVar(&args.GoHeaderFile, "go-header-file", "", + "the path to a file containing boilerplate header text; the string \"YEAR\" will be replaced with the current 4-digit year") +} + +// Validate checks the given arguments. +func (args *Args) Validate() error { + if len(args.OutputDir) == 0 { + return fmt.Errorf("--output-dir must be specified") + } + if len(args.OutputPkg) == 0 { + return fmt.Errorf("--output-pkg must be specified") + } + return nil +} diff --git a/code-generator/cmd/lister-gen/generators/expansion.go b/code-generator/cmd/lister-gen/generators/expansion.go new file mode 100644 index 000000000..4755f2ed1 --- /dev/null +++ b/code-generator/cmd/lister-gen/generators/expansion.go @@ -0,0 +1,73 @@ +/* +Copyright 2016 The Kubernetes 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" + "os" + "path/filepath" + "strings" + + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/types" + "k8s.io/klog/v2" + + "k8s.io/code-generator/cmd/client-gen/generators/util" +) + +// expansionGenerator produces a file for a expansion interfaces. +type expansionGenerator struct { + generator.GoGenerator + outputPath string + types []*types.Type +} + +// We only want to call GenerateType() once per group. +func (g *expansionGenerator) Filter(c *generator.Context, t *types.Type) bool { + return t == g.types[0] +} + +func (g *expansionGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + for _, t := range g.types { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + manualFile := filepath.Join(g.outputPath, strings.ToLower(t.Name.Name+"_expansion.go")) + if _, err := os.Stat(manualFile); err == nil { + klog.V(4).Infof("file %q exists, not generating", manualFile) + } else if os.IsNotExist(err) { + sw.Do(expansionInterfaceTemplate, t) + if !tags.NonNamespaced { + sw.Do(namespacedExpansionInterfaceTemplate, t) + } + } else { + return err + } + } + return sw.Error() +} + +var expansionInterfaceTemplate = ` +// $.|public$ListerExpansion allows custom methods to be added to +// $.|public$Lister. +type $.|public$ListerExpansion interface {} +` + +var namespacedExpansionInterfaceTemplate = ` +// $.|public$NamespaceListerExpansion allows custom methods to be added to +// $.|public$NamespaceLister. +type $.|public$NamespaceListerExpansion interface {} +` diff --git a/code-generator/cmd/lister-gen/generators/lister.go b/code-generator/cmd/lister-gen/generators/lister.go new file mode 100644 index 000000000..a5beb2a7f --- /dev/null +++ b/code-generator/cmd/lister-gen/generators/lister.go @@ -0,0 +1,333 @@ +/* +Copyright 2016 The Kubernetes 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 ( + "fmt" + "io" + "path" + "path/filepath" + "strings" + + "k8s.io/code-generator/cmd/client-gen/generators/util" + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/code-generator/cmd/lister-gen/args" + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + "k8s.io/klog/v2" +) + +// NameSystems returns the name system used by the generators in this package. +func NameSystems(pluralExceptions map[string]string) namer.NameSystems { + return namer.NameSystems{ + "public": namer.NewPublicNamer(0), + "private": namer.NewPrivateNamer(0), + "raw": namer.NewRawNamer("", nil), + "publicPlural": namer.NewPublicPluralNamer(pluralExceptions), + "allLowercasePlural": namer.NewAllLowercasePluralNamer(pluralExceptions), + "lowercaseSingular": &lowercaseSingularNamer{}, + } +} + +// 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) +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +// GetTargets makes the client target definition. +func GetTargets(context *generator.Context, args *args.Args) []generator.Target { + boilerplate, err := gengo.GoBoilerplate(args.GoHeaderFile, "", gengo.StdGeneratedBy) + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + var targetList []generator.Target + for _, inputPkg := range context.Inputs { + p := context.Universe.Package(inputPkg) + + objectMeta, internal, err := objectMetaForPackage(p) + if err != nil { + klog.Fatal(err) + } + if objectMeta == nil { + // no types in this package had genclient + continue + } + + var gv clientgentypes.GroupVersion + var internalGVPkg string + + if internal { + lastSlash := strings.LastIndex(p.Path, "/") + if lastSlash == -1 { + klog.Fatalf("error constructing internal group version for package %q", p.Path) + } + gv.Group = clientgentypes.Group(p.Path[lastSlash+1:]) + internalGVPkg = p.Path + } else { + parts := strings.Split(p.Path, "/") + gv.Group = clientgentypes.Group(parts[len(parts)-2]) + gv.Version = clientgentypes.Version(parts[len(parts)-1]) + + internalGVPkg = strings.Join(parts[0:len(parts)-1], "/") + } + groupPackageName := strings.ToLower(gv.Group.NonEmpty()) + + // 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 := gengo.ExtractCommentTags("+", p.Comments)["groupName"]; override != nil { + gv.Group = clientgentypes.Group(strings.SplitN(override[0], ".", 2)[0]) + } + + var typesToGenerate []*types.Type + for _, t := range p.Types { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if !tags.GenerateClient || !tags.HasVerb("list") || !tags.HasVerb("get") { + continue + } + typesToGenerate = append(typesToGenerate, t) + } + if len(typesToGenerate) == 0 { + continue + } + orderer := namer.Orderer{Namer: namer.NewPrivateNamer(0)} + typesToGenerate = orderer.OrderTypes(typesToGenerate) + + subdir := []string{groupPackageName, strings.ToLower(gv.Version.NonEmpty())} + outputDir := filepath.Join(args.OutputDir, filepath.Join(subdir...)) + outputPkg := path.Join(args.OutputPkg, path.Join(subdir...)) + targetList = append(targetList, &generator.SimpleTarget{ + PkgName: strings.ToLower(gv.Version.NonEmpty()), + PkgPath: outputPkg, + PkgDir: outputDir, + HeaderComment: boilerplate, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + tags := util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + return tags.GenerateClient && tags.HasVerb("list") && tags.HasVerb("get") + }, + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + generators = append(generators, &expansionGenerator{ + GoGenerator: generator.GoGenerator{ + OutputFilename: "expansion_generated.go", + }, + outputPath: outputDir, + types: typesToGenerate, + }) + + for _, t := range typesToGenerate { + generators = append(generators, &listerGenerator{ + GoGenerator: generator.GoGenerator{ + OutputFilename: strings.ToLower(t.Name.Name) + ".go", + }, + outputPackage: outputPkg, + groupVersion: gv, + internalGVPkg: internalGVPkg, + typeToGenerate: t, + imports: generator.NewImportTrackerForPackage(outputPkg), + objectMeta: objectMeta, + }) + } + return generators + }, + }) + } + + return targetList +} + +// objectMetaForPackage returns the type of ObjectMeta used by package p. +func objectMetaForPackage(p *types.Package) (*types.Type, bool, error) { + generatingForPackage := false + for _, t := range p.Types { + // filter out types which don't have genclient. + if !util.MustParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)).GenerateClient { + continue + } + generatingForPackage = true + for _, member := range t.Members { + if member.Name == "ObjectMeta" { + return member.Type, isInternal(member), nil + } + } + } + if generatingForPackage { + return nil, false, fmt.Errorf("unable to find ObjectMeta for any types in package %s", p.Path) + } + return nil, false, nil +} + +// isInternal returns true if the tags for a member do not contain a json tag +func isInternal(m types.Member) bool { + return !strings.Contains(m.Tags, "json") +} + +// listerGenerator produces a file of listers for a given GroupVersion and +// type. +type listerGenerator struct { + generator.GoGenerator + outputPackage string + groupVersion clientgentypes.GroupVersion + internalGVPkg string + typeToGenerate *types.Type + imports namer.ImportTracker + objectMeta *types.Type +} + +var _ generator.Generator = &listerGenerator{} + +func (g *listerGenerator) Filter(c *generator.Context, t *types.Type) bool { + return t == g.typeToGenerate +} + +func (g *listerGenerator) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *listerGenerator) Imports(c *generator.Context) (imports []string) { + imports = append(imports, g.imports.ImportLines()...) + return +} + +func (g *listerGenerator) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + sw := generator.NewSnippetWriter(w, c, "$", "$") + + klog.V(5).Infof("processing type %v", t) + m := map[string]interface{}{ + "Resource": c.Universe.Function(types.Name{Package: t.Name.Package, Name: "Resource"}), + "labelsSelector": c.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/labels", Name: "Selector"}), + "listersResourceIndexer": c.Universe.Function(types.Name{Package: "k8s.io/client-go/listers", Name: "ResourceIndexer"}), + "listersNew": c.Universe.Function(types.Name{Package: "k8s.io/client-go/listers", Name: "New"}), + "listersNewNamespaced": c.Universe.Function(types.Name{Package: "k8s.io/client-go/listers", Name: "NewNamespaced"}), + "cacheIndexer": c.Universe.Type(types.Name{Package: "k8s.io/client-go/tools/cache", Name: "Indexer"}), + "type": t, + "objectMeta": g.objectMeta, + } + + tags, err := util.ParseClientGenTags(append(t.SecondClosestCommentLines, t.CommentLines...)) + if err != nil { + return err + } + + if tags.NonNamespaced { + sw.Do(typeListerInterfaceNonNamespaced, m) + } else { + sw.Do(typeListerInterface, m) + } + + sw.Do(typeListerStruct, m) + sw.Do(typeListerConstructor, m) + + if tags.NonNamespaced { + return sw.Error() + } + + sw.Do(typeListerNamespaceLister, m) + sw.Do(namespaceListerInterface, m) + sw.Do(namespaceListerStruct, m) + + return sw.Error() +} + +var typeListerInterface = ` +// $.type|public$Lister helps list $.type|publicPlural$. +// All objects returned here must be treated as read-only. +type $.type|public$Lister interface { + // List lists all $.type|publicPlural$ in the indexer. + // Objects returned here must be treated as read-only. + List(selector $.labelsSelector|raw$) (ret []*$.type|raw$, err error) + // $.type|publicPlural$ returns an object that can list and get $.type|publicPlural$. + $.type|publicPlural$(namespace string) $.type|public$NamespaceLister + $.type|public$ListerExpansion +} +` + +var typeListerInterfaceNonNamespaced = ` +// $.type|public$Lister helps list $.type|publicPlural$. +// All objects returned here must be treated as read-only. +type $.type|public$Lister interface { + // List lists all $.type|publicPlural$ in the indexer. + // Objects returned here must be treated as read-only. + List(selector $.labelsSelector|raw$) (ret []*$.type|raw$, err error) + // Get retrieves the $.type|public$ from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*$.type|raw$, error) + $.type|public$ListerExpansion +} +` + +// This embeds a typed resource indexer instead of aliasing, so that the struct +// is available as a receiver for methods specific to the generated type +// (from the corresponding expansion interface). +var typeListerStruct = ` +// $.type|private$Lister implements the $.type|public$Lister interface. +type $.type|private$Lister struct { + $.listersResourceIndexer|raw$[*$.type|raw$] +} +` + +var typeListerConstructor = ` +// New$.type|public$Lister returns a new $.type|public$Lister. +func New$.type|public$Lister(indexer $.cacheIndexer|raw$) $.type|public$Lister { + return &$.type|private$Lister{$.listersNew|raw$[*$.type|raw$](indexer, $.Resource|raw$("$.type|lowercaseSingular$"))} +} +` + +var typeListerNamespaceLister = ` +// $.type|publicPlural$ returns an object that can list and get $.type|publicPlural$. +func (s *$.type|private$Lister) $.type|publicPlural$(namespace string) $.type|public$NamespaceLister { + return $.type|private$NamespaceLister{$.listersNewNamespaced|raw$[*$.type|raw$](s.ResourceIndexer, namespace)} +} +` + +var namespaceListerInterface = ` +// $.type|public$NamespaceLister helps list and get $.type|publicPlural$. +// All objects returned here must be treated as read-only. +type $.type|public$NamespaceLister interface { + // List lists all $.type|publicPlural$ in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector $.labelsSelector|raw$) (ret []*$.type|raw$, err error) + // Get retrieves the $.type|public$ from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*$.type|raw$, error) + $.type|public$NamespaceListerExpansion +} +` + +// This embeds a typed namespaced resource indexer instead of aliasing, so that the struct +// is available as a receiver for methods specific to the generated type +// (from the corresponding expansion interface). +var namespaceListerStruct = ` +// $.type|private$NamespaceLister implements the $.type|public$NamespaceLister +// interface. +type $.type|private$NamespaceLister struct { + $.listersResourceIndexer|raw$[*$.type|raw$] +} +` diff --git a/code-generator/cmd/lister-gen/main.go b/code-generator/cmd/lister-gen/main.go new file mode 100644 index 000000000..8dde18bab --- /dev/null +++ b/code-generator/cmd/lister-gen/main.go @@ -0,0 +1,59 @@ +/* +Copyright 2016 The Kubernetes 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" + + "github.com/spf13/pflag" + "k8s.io/code-generator/cmd/lister-gen/args" + "k8s.io/code-generator/cmd/lister-gen/generators" + "k8s.io/code-generator/pkg/util" + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/klog/v2" +) + +func main() { + klog.InitFlags(nil) + args := args.New() + + args.AddFlags(pflag.CommandLine) + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + if err := args.Validate(); err != nil { + klog.Fatalf("Error: %v", err) + } + + myTargets := func(context *generator.Context) []generator.Target { + return generators.GetTargets(context, args) + } + + // Run it. + if err := gengo.Execute( + generators.NameSystems(util.PluralExceptionListToMapOrDie(args.PluralExceptions)), + generators.DefaultNameSystem(), + myTargets, + gengo.StdBuildTag, + pflag.Args(), + ); err != nil { + klog.Fatalf("Error: %v", err) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/code-generator/cmd/prerelease-lifecycle-gen/args/args.go b/code-generator/cmd/prerelease-lifecycle-gen/args/args.go new file mode 100644 index 000000000..412dd534c --- /dev/null +++ b/code-generator/cmd/prerelease-lifecycle-gen/args/args.go @@ -0,0 +1,50 @@ +/* +Copyright 2020 The Kubernetes 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" +) + +type Args struct { + OutputFile string + GoHeaderFile string +} + +// New returns default arguments for the generator. +func New() *Args { + return &Args{} +} + +// AddFlags add the generator flags to the flag set. +func (args *Args) AddFlags(fs *pflag.FlagSet) { + fs.StringVar(&args.OutputFile, "output-file", "generated.prerelease_lifecycle.go", + "the name of the file to be generated") + fs.StringVar(&args.GoHeaderFile, "go-header-file", "", + "the path to a file containing boilerplate header text; the string \"YEAR\" will be replaced with the current 4-digit year") +} + +// Validate checks the given arguments. +func (args *Args) Validate() error { + if len(args.OutputFile) == 0 { + return fmt.Errorf("--output-file must be specified") + } + + return nil +} diff --git a/code-generator/cmd/prerelease-lifecycle-gen/main.go b/code-generator/cmd/prerelease-lifecycle-gen/main.go new file mode 100644 index 000000000..717b6b076 --- /dev/null +++ b/code-generator/cmd/prerelease-lifecycle-gen/main.go @@ -0,0 +1,76 @@ +/* +Copyright 2020 The Kubernetes 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. +*/ + +// prerelease-lifecycle-gen is a tool for auto-generating api-status.csv files. +// +// Given a list of input directories, it will create a zz_api_status.go file for all beta APIs which indicates the kinds, +// the release it was introduced, the release it will be deprecated, and the release it will be removed. +// +// Generation is governed by comment tags in the source. Any package may +// request Status generation by including a comment in the file-comments of +// one file, of the form: +// +// // +k8s:prerelease-lifecycle-gen=true +// +// // +k8s:prerelease-lifecycle-gen:introduced=1.19 +// // +k8s:prerelease-lifecycle-gen:deprecated=1.22 +// // +k8s:prerelease-lifecycle-gen:removed=1.25 +// // +k8s:prerelease-lifecycle-gen:replacement=wardle.example.com,v1,Flunder +// +// Note that registration is a whole-package option, and is not available for +// individual types. +package main + +import ( + "flag" + + "github.com/spf13/pflag" + "k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args" + statusgenerators "k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators" + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/klog/v2" +) + +func main() { + klog.InitFlags(nil) + args := args.New() + + args.AddFlags(pflag.CommandLine) + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + if err := args.Validate(); err != nil { + klog.Fatalf("Error: %v", err) + } + + myTargets := func(context *generator.Context) []generator.Target { + return statusgenerators.GetTargets(context, args) + } + + // Run it. + if err := gengo.Execute( + statusgenerators.NameSystems(), + statusgenerators.DefaultNameSystem(), + myTargets, + gengo.StdBuildTag, + pflag.Args(), + ); err != nil { + klog.Fatalf("Error: %v", err) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators/status.go b/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators/status.go new file mode 100644 index 000000000..2213a9944 --- /dev/null +++ b/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators/status.go @@ -0,0 +1,497 @@ +/* +Copyright 2020 The Kubernetes 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 prereleaselifecyclegenerators + +import ( + "fmt" + "io" + "path" + "regexp" + "strconv" + "strings" + + "k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args" + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" + + "k8s.io/klog/v2" +) + +// This is the comment tag that carries parameters for API status generation. Because the cadence is fixed, we can predict +// with near certainty when this lifecycle happens as the API is introduced. +const ( + tagEnabledName = "k8s:prerelease-lifecycle-gen" + introducedTagName = tagEnabledName + ":introduced" + deprecatedTagName = tagEnabledName + ":deprecated" + removedTagName = tagEnabledName + ":removed" + + replacementTagName = tagEnabledName + ":replacement" +) + +// enabledTagValue holds parameters from a tagName tag. +type tagValue struct { + value string +} + +func extractEnabledTypeTag(t *types.Type) *tagValue { + comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...) + return extractTag(tagEnabledName, comments) +} + +func tagExists(tagName string, t *types.Type) bool { + comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...) + rawTag := extractTag(tagName, comments) + return rawTag != nil +} + +func extractKubeVersionTag(tagName string, t *types.Type) (*tagValue, int, int, error) { + comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...) + rawTag := extractTag(tagName, comments) + if rawTag == nil || len(rawTag.value) == 0 { + return nil, -1, -1, fmt.Errorf("%v missing %v=Version tag", t, tagName) + } + + splitValue := strings.Split(rawTag.value, ".") + if len(splitValue) != 2 || len(splitValue[0]) == 0 || len(splitValue[1]) == 0 { + return nil, -1, -1, fmt.Errorf("%v format must match %v=xx.yy tag", t, tagName) + } + major, err := strconv.ParseInt(splitValue[0], 10, 32) + if err != nil { + return nil, -1, -1, fmt.Errorf("%v format must match %v=xx.yy : %w", t, tagName, err) + } + minor, err := strconv.ParseInt(splitValue[1], 10, 32) + if err != nil { + return nil, -1, -1, fmt.Errorf("%v format must match %v=xx.yy : %w", t, tagName, err) + } + + return rawTag, int(major), int(minor), nil +} + +func extractIntroducedTag(t *types.Type) (*tagValue, int, int, error) { + return extractKubeVersionTag(introducedTagName, t) +} + +func extractDeprecatedTag(t *types.Type) (*tagValue, int, int, error) { + return extractKubeVersionTag(deprecatedTagName, t) +} + +func extractRemovedTag(t *types.Type) (*tagValue, int, int, error) { + return extractKubeVersionTag(removedTagName, t) +} + +func extractReplacementTag(t *types.Type) (group, version, kind string, hasReplacement bool, err error) { + comments := append(append([]string{}, t.SecondClosestCommentLines...), t.CommentLines...) + + tagVals := gengo.ExtractCommentTags("+", comments)[replacementTagName] + if len(tagVals) == 0 { + // No match for the tag. + return "", "", "", false, nil + } + // If there are multiple values, abort. + if len(tagVals) > 1 { + return "", "", "", false, fmt.Errorf("found %d %s tags: %q", len(tagVals), replacementTagName, tagVals) + } + tagValue := tagVals[0] + parts := strings.Split(tagValue, ",") + if len(parts) != 3 { + return "", "", "", false, fmt.Errorf(`%s value must be ",,", got %q`, replacementTagName, tagValue) + } + group, version, kind = parts[0], parts[1], parts[2] + if len(version) == 0 || len(kind) == 0 { + return "", "", "", false, fmt.Errorf(`%s value must be ",,", got %q`, replacementTagName, tagValue) + } + // sanity check the group + if strings.ToLower(group) != group { + return "", "", "", false, fmt.Errorf(`replacement group must be all lower-case, got %q`, group) + } + // sanity check the version + if !strings.HasPrefix(version, "v") || strings.ToLower(version) != version { + return "", "", "", false, fmt.Errorf(`replacement version must start with "v" and be all lower-case, got %q`, version) + } + // sanity check the kind + if strings.ToUpper(kind[:1]) != kind[:1] { + return "", "", "", false, fmt.Errorf(`replacement kind must start with uppercase-letter, got %q`, kind) + } + return group, version, kind, true, nil +} + +func extractTag(tagName string, comments []string) *tagValue { + tagVals := gengo.ExtractCommentTags("+", comments)[tagName] + if tagVals == nil { + // No match for the tag. + return nil + } + // If there are multiple values, abort. + if len(tagVals) > 1 { + klog.Fatalf("Found %d %s tags: %q", len(tagVals), tagName, tagVals) + } + + // If we got here we are returning something. + tag := &tagValue{} + + // Get the primary value. + parts := strings.Split(tagVals[0], ",") + if len(parts) >= 1 { + tag.value = parts[0] + } + + // Parse extra arguments. + parts = parts[1:] + for i := range parts { + kv := strings.SplitN(parts[i], "=", 2) + k := kv[0] + if k != "" { + klog.Fatalf("Unsupported %s param: %q", tagName, parts[i]) + } + } + return tag +} + +// NameSystems returns the name system used by the generators in this package. +func NameSystems() namer.NameSystems { + return namer.NameSystems{ + "public": namer.NewPublicNamer(1), + "raw": namer.NewRawNamer("", nil), + } +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +// GetTargets makes the target definition. +func GetTargets(context *generator.Context, args *args.Args) []generator.Target { + boilerplate, err := gengo.GoBoilerplate(args.GoHeaderFile, gengo.StdBuildTag, gengo.StdGeneratedBy) + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + targets := []generator.Target{} + + for _, i := range context.Inputs { + klog.V(5).Infof("Considering pkg %q", i) + + pkg := context.Universe[i] + + ptag := extractTag(tagEnabledName, pkg.Comments) + pkgNeedsGeneration := false + if ptag != nil { + pkgNeedsGeneration, err = strconv.ParseBool(ptag.value) + if err != nil { + klog.Fatalf("Package %v: unsupported %s value: %q :%v", i, tagEnabledName, ptag.value, err) + } + } + if !pkgNeedsGeneration { + klog.V(5).Infof(" skipping package") + continue + } + klog.V(3).Infof("Generating package %q", pkg.Path) + + // If the pkg-scoped tag says to generate, we can skip scanning types. + if !pkgNeedsGeneration { + // If the pkg-scoped tag did not exist, scan all types for one that + // explicitly wants generation. + for _, t := range pkg.Types { + klog.V(5).Infof(" considering type %q", t.Name.String()) + ttag := extractEnabledTypeTag(t) + if ttag != nil && ttag.value == "true" { + klog.V(5).Infof(" tag=true") + if !isAPIType(t) { + klog.Fatalf("Type %v requests prerelease generation but is not an API type", t) + } + pkgNeedsGeneration = true + break + } + } + } + + if pkgNeedsGeneration { + targets = append(targets, + &generator.SimpleTarget{ + PkgName: strings.Split(path.Base(pkg.Path), ".")[0], + PkgPath: pkg.Path, + PkgDir: pkg.Dir, // output pkg is the same as the input + HeaderComment: boilerplate, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + return t.Name.Package == pkg.Path + }, + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + return []generator.Generator{ + NewPrereleaseLifecycleGen(args.OutputFile, pkg.Path), + } + }, + }) + } + } + return targets +} + +// genDeepCopy produces a file with autogenerated deep-copy functions. +type genPreleaseLifecycle struct { + generator.GoGenerator + targetPackage string + imports namer.ImportTracker + typesForInit []*types.Type +} + +// NewPrereleaseLifecycleGen creates a generator for the prerelease-lifecycle-generator +func NewPrereleaseLifecycleGen(outputFilename, targetPackage string) generator.Generator { + return &genPreleaseLifecycle{ + GoGenerator: generator.GoGenerator{ + OutputFilename: outputFilename, + }, + targetPackage: targetPackage, + imports: generator.NewImportTracker(), + typesForInit: make([]*types.Type, 0), + } +} + +func (g *genPreleaseLifecycle) Namers(c *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "public": namer.NewPublicNamer(1), + "intrapackage": namer.NewPublicNamer(0), + "raw": namer.NewRawNamer("", nil), + } +} + +func (g *genPreleaseLifecycle) Filter(c *generator.Context, t *types.Type) bool { + // Filter out types not being processed or not copyable within the package. + if !isAPIType(t) { + klog.V(2).Infof("Type %v is not a valid target for status", t) + return false + } + g.typesForInit = append(g.typesForInit, t) + return true +} + +// versionMethod returns the signature of an () method, nil or an error +// if the type is wrong. Introduced() allows more efficient deep copy +// implementations to be defined by the type's author. The correct signature +// +// func (t *T) () string +func versionMethod(methodName string, t *types.Type) (*types.Signature, error) { + f, found := t.Methods[methodName] + if !found { + return nil, nil + } + if len(f.Signature.Parameters) != 0 { + return nil, fmt.Errorf("type %v: invalid %v signature, expected no parameters", t, methodName) + } + if len(f.Signature.Results) != 2 { + return nil, fmt.Errorf("type %v: invalid %v signature, expected exactly two result types", t, methodName) + } + + ptrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Kind == types.Pointer && f.Signature.Receiver.Elem.Name == t.Name + nonPtrRcvr := f.Signature.Receiver != nil && f.Signature.Receiver.Name == t.Name + + if !ptrRcvr && !nonPtrRcvr { + // this should never happen + return nil, fmt.Errorf("type %v: invalid %v signature, expected a receiver of type %s or *%s", t, methodName, t.Name.Name, t.Name.Name) + } + + return f.Signature, nil +} + +// versionedMethodOrDie returns the signature of a () method, nil or calls klog.Fatalf +// if the type is wrong. +func versionedMethodOrDie(methodName string, t *types.Type) *types.Signature { + ret, err := versionMethod(methodName, t) + if err != nil { + klog.Fatal(err) + } + return ret +} + +// isAPIType indicates whether or not a type could be used to serve an API. That means, "does it have TypeMeta". +// This doesn't mean the type is served, but we will handle all TypeMeta types. +func isAPIType(t *types.Type) bool { + // Filter out private types. + if namer.IsPrivateGoName(t.Name.Name) { + return false + } + + if t.Kind != types.Struct { + return false + } + + for _, currMember := range t.Members { + if currMember.Embedded && currMember.Name == "TypeMeta" { + return true + } + } + + if t.Kind == types.Alias { + return isAPIType(t.Underlying) + } + + return false +} + +func (g *genPreleaseLifecycle) isOtherPackage(pkg string) bool { + if pkg == g.targetPackage { + return false + } + if strings.HasSuffix(pkg, "\""+g.targetPackage+"\"") { + return false + } + return true +} + +func (g *genPreleaseLifecycle) Imports(c *generator.Context) (imports []string) { + importLines := []string{} + for _, singleImport := range g.imports.ImportLines() { + if g.isOtherPackage(singleImport) { + importLines = append(importLines, singleImport) + } + } + return importLines +} + +var ( + isGAVersionRegex = regexp.MustCompile(`^v\d+$`) +) + +func (g *genPreleaseLifecycle) argsFromType(c *generator.Context, t *types.Type) (generator.Args, error) { + a := generator.Args{ + "type": t, + } + _, introducedMajor, introducedMinor, err := extractIntroducedTag(t) + if err != nil { + return nil, err + } + + // Take version from package last segment. + // Use heuristic to determine whether the package is GA or prerelease. + // If the package is GA, the version matches the format vN where N is a number. + version := path.Base(t.Name.Package) + isGAVersion := isGAVersionRegex.MatchString(version) + + a = a. + With("introducedMajor", introducedMajor). + With("introducedMinor", introducedMinor) + + // compute based on our policy + hasDeprecated := tagExists(deprecatedTagName, t) + hasRemoved := tagExists(removedTagName, t) + + deprecatedMajor := introducedMajor + deprecatedMinor := introducedMinor + 3 + // if someone intentionally override the deprecation release + if hasDeprecated { + _, deprecatedMajor, deprecatedMinor, err = extractDeprecatedTag(t) + if err != nil { + return nil, err + } + } + + if !isGAVersion || hasDeprecated { + a = a. + With("deprecatedMajor", deprecatedMajor). + With("deprecatedMinor", deprecatedMinor) + } + + // compute based on our policy + removedMajor := deprecatedMajor + removedMinor := deprecatedMinor + 3 + // if someone intentionally override the removed release + if hasRemoved { + _, removedMajor, removedMinor, err = extractRemovedTag(t) + if err != nil { + return nil, err + } + } + + if !isGAVersion || hasRemoved { + a = a. + With("removedMajor", removedMajor). + With("removedMinor", removedMinor) + } + + replacementGroup, replacementVersion, replacementKind, hasReplacement, err := extractReplacementTag(t) + if err != nil { + return nil, err + } + if hasReplacement { + gvkType := c.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/runtime/schema", Name: "GroupVersionKind"}) + g.imports.AddType(gvkType) + a = a. + With("replacementGroup", replacementGroup). + With("replacementVersion", replacementVersion). + With("replacementKind", replacementKind). + With("GroupVersionKind", gvkType) + } + + return a, nil +} + +func (g *genPreleaseLifecycle) Init(c *generator.Context, w io.Writer) error { + return nil +} + +func (g *genPreleaseLifecycle) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { + klog.V(3).Infof("Generating prerelease-lifecycle for type %v", t) + + sw := generator.NewSnippetWriter(w, c, "$", "$") + args, err := g.argsFromType(c, t) + if err != nil { + return err + } + + if versionedMethodOrDie("APILifecycleIntroduced", t) == nil { + sw.Do("// APILifecycleIntroduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison.\n", args) + sw.Do("// It is controlled by \""+introducedTagName+"\" tags in types.go.\n", args) + sw.Do("func (in *$.type|intrapackage$) APILifecycleIntroduced() (major, minor int) {\n", args) + sw.Do(" return $.introducedMajor$, $.introducedMinor$\n", args) + sw.Do("}\n\n", nil) + } + + if _, hasDeprecated := args["deprecatedMajor"]; hasDeprecated { + if versionedMethodOrDie("APILifecycleDeprecated", t) == nil { + sw.Do("// APILifecycleDeprecated is an autogenerated function, returning the release in which the API struct was or will be deprecated as int versions of major and minor for comparison.\n", args) + sw.Do("// It is controlled by \""+deprecatedTagName+"\" tags in types.go or \""+introducedTagName+"\" plus three minor.\n", args) + sw.Do("func (in *$.type|intrapackage$) APILifecycleDeprecated() (major, minor int) {\n", args) + sw.Do(" return $.deprecatedMajor$, $.deprecatedMinor$\n", args) + sw.Do("}\n\n", nil) + } + } + + if _, hasReplacement := args["replacementKind"]; hasReplacement { + if versionedMethodOrDie("APILifecycleReplacement", t) == nil { + sw.Do("// APILifecycleReplacement is an autogenerated function, returning the group, version, and kind that should be used instead of this deprecated type.\n", args) + sw.Do("// It is controlled by \""+replacementTagName+"=,,\" tags in types.go.\n", args) + sw.Do("func (in *$.type|intrapackage$) APILifecycleReplacement() ($.GroupVersionKind|raw$) {\n", args) + sw.Do(" return $.GroupVersionKind|raw${Group:\"$.replacementGroup$\", Version:\"$.replacementVersion$\", Kind:\"$.replacementKind$\"}\n", args) + sw.Do("}\n\n", nil) + } + } + + if _, hasRemoved := args["removedMajor"]; hasRemoved { + if versionedMethodOrDie("APILifecycleRemoved", t) == nil { + sw.Do("// APILifecycleRemoved is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison.\n", args) + sw.Do("// It is controlled by \""+removedTagName+"\" tags in types.go or \""+deprecatedTagName+"\" plus three minor.\n", args) + sw.Do("func (in *$.type|intrapackage$) APILifecycleRemoved() (major, minor int) {\n", args) + sw.Do(" return $.removedMajor$, $.removedMinor$\n", args) + sw.Do("}\n\n", nil) + } + } + + return sw.Error() +} diff --git a/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators/status_test.go b/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators/status_test.go new file mode 100644 index 000000000..96e392047 --- /dev/null +++ b/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators/status_test.go @@ -0,0 +1,798 @@ +/* +Copyright 2023 The Kubernetes 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 prereleaselifecyclegenerators + +import ( + "fmt" + "reflect" + "strconv" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/types" + "k8s.io/klog/v2" +) + +var mockType = &types.Type{ + CommentLines: []string{ + "RandomType defines a random structure in Kubernetes", + "It should be used just when you need something different than 42", + }, + SecondClosestCommentLines: []string{}, +} + +func TestArgsFromType(t *testing.T) { + type testcase struct { + name string + t *types.Type + expected generator.Args + expectedError string + } + + tests := []testcase{ + { + name: "no comments", + t: &types.Type{ + Name: types.Name{ + Name: "Simple", + Package: "k8s.io/apis/core/v1", + }, + }, + expectedError: `missing`, + }, + { + name: "GA type", + t: &types.Type{ + Name: types.Name{ + Name: "Simple", + Package: "k8s.io/apis/core/v1", + }, + CommentLines: []string{ + "+k8s:prerelease-lifecycle-gen:introduced=1.5", + }, + }, + expected: generator.Args{ + "introducedMajor": 1, + "introducedMinor": 5, + }, + }, + { + name: "GA type v2", + t: &types.Type{ + Name: types.Name{ + Name: "Simple", + Package: "k8s.io/apis/core/v2", + }, + CommentLines: []string{ + "+k8s:prerelease-lifecycle-gen:introduced=1.5", + }, + }, + expected: generator.Args{ + "introducedMajor": 1, + "introducedMinor": 5, + }, + }, + { + name: "GA type - explicit deprecated", + t: &types.Type{ + Name: types.Name{ + Name: "Simple", + Package: "k8s.io/apis/core/v1", + }, + CommentLines: []string{ + "+k8s:prerelease-lifecycle-gen:introduced=1.5", + "+k8s:prerelease-lifecycle-gen:deprecated=1.7", + }, + }, + expected: generator.Args{ + "introducedMajor": 1, + "introducedMinor": 5, + "deprecatedMajor": 1, + "deprecatedMinor": 7, + }, + }, + { + name: "GA type - explicit removed", + t: &types.Type{ + Name: types.Name{ + Name: "Simple", + Package: "k8s.io/apis/core/v1", + }, + CommentLines: []string{ + "+k8s:prerelease-lifecycle-gen:introduced=1.5", + "+k8s:prerelease-lifecycle-gen:removed=1.9", + }, + }, + expected: generator.Args{ + "introducedMajor": 1, + "introducedMinor": 5, + "removedMajor": 1, + "removedMinor": 9, + }, + }, + { + name: "GA type - explicit", + t: &types.Type{ + Name: types.Name{ + Name: "Simple", + Package: "k8s.io/apis/core/v1", + }, + CommentLines: []string{ + "+k8s:prerelease-lifecycle-gen:introduced=1.5", + "+k8s:prerelease-lifecycle-gen:deprecated=1.7", + "+k8s:prerelease-lifecycle-gen:removed=1.9", + }, + }, + expected: generator.Args{ + "introducedMajor": 1, + "introducedMinor": 5, + "deprecatedMajor": 1, + "deprecatedMinor": 7, + "removedMajor": 1, + "removedMinor": 9, + }, + }, + { + name: "beta type - defaulted", + t: &types.Type{ + Name: types.Name{ + Name: "Simple", + Package: "k8s.io/apis/core/v1beta1", + }, + CommentLines: []string{ + "+k8s:prerelease-lifecycle-gen:introduced=1.5", + }, + }, + expected: generator.Args{ + "introducedMajor": 1, + "introducedMinor": 5, + "deprecatedMajor": 1, + "deprecatedMinor": 8, + "removedMajor": 1, + "removedMinor": 11, + }, + }, + { + name: "beta type - explicit", + t: &types.Type{ + Name: types.Name{ + Name: "Simple", + Package: "k8s.io/apis/core/v1beta1", + }, + CommentLines: []string{ + "+k8s:prerelease-lifecycle-gen:introduced=1.5", + "+k8s:prerelease-lifecycle-gen:deprecated=1.7", + "+k8s:prerelease-lifecycle-gen:removed=1.9", + }, + }, + expected: generator.Args{ + "introducedMajor": 1, + "introducedMinor": 5, + "deprecatedMajor": 1, + "deprecatedMinor": 7, + "removedMajor": 1, + "removedMinor": 9, + }, + }, + { + name: "beta type - explicit deprecated only", + t: &types.Type{ + Name: types.Name{ + Name: "Simple", + Package: "k8s.io/apis/core/v1beta1", + }, + CommentLines: []string{ + "+k8s:prerelease-lifecycle-gen:introduced=1.5", + "+k8s:prerelease-lifecycle-gen:deprecated=1.7", + }, + }, + expected: generator.Args{ + "introducedMajor": 1, + "introducedMinor": 5, + "deprecatedMajor": 1, + "deprecatedMinor": 7, + "removedMajor": 1, + "removedMinor": 10, + }, + }, + { + name: "beta type - explicit removed only", + t: &types.Type{ + Name: types.Name{ + Name: "Simple", + Package: "k8s.io/apis/core/v1beta1", + }, + CommentLines: []string{ + "+k8s:prerelease-lifecycle-gen:introduced=1.5", + "+k8s:prerelease-lifecycle-gen:removed=1.9", + }, + }, + expected: generator.Args{ + "introducedMajor": 1, + "introducedMinor": 5, + "deprecatedMajor": 1, + "deprecatedMinor": 8, + "removedMajor": 1, + "removedMinor": 9, + }, + }, + { + name: "alpha type - defaulted", + t: &types.Type{ + Name: types.Name{ + Name: "Simple", + Package: "k8s.io/apis/core/v1alpha1", + }, + CommentLines: []string{ + "+k8s:prerelease-lifecycle-gen:introduced=1.5", + }, + }, + expected: generator.Args{ + "introducedMajor": 1, + "introducedMinor": 5, + "deprecatedMajor": 1, + "deprecatedMinor": 8, + "removedMajor": 1, + "removedMinor": 11, + }, + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + if test.expected != nil { + test.expected["type"] = test.t + } + gen := genPreleaseLifecycle{} + args, err := gen.argsFromType(nil, test.t) + if test.expectedError != "" { + if err == nil { + t.Errorf("expected error, got none") + } else if !strings.Contains(err.Error(), test.expectedError) { + t.Errorf("expected error %q, got %q", test.expectedError, err.Error()) + } + return + } + if err != nil { + t.Errorf("unexpected error: %v", err) + } + if diff := cmp.Diff(test.expected, args); diff != "" { + t.Error(diff) + } + }) + } +} + +func Test_extractKubeVersionTag(t *testing.T) { + oldKlogOsExit := klog.OsExit + defer func() { + klog.OsExit = oldKlogOsExit + }() + klog.OsExit = customExit + + tests := []struct { + name string + tagName string + tagComments []string + wantValue *tagValue + wantMajor int + wantMinor int + wantErr bool + wantFatal bool + }{ + { + name: "not found tag should generate an error", + tagName: "someVersionTag:version", + tagComments: []string{ + "+someOtherTag:version=1.5", + }, + wantValue: nil, + wantErr: true, + }, + { + name: "found tag should return correctly", + tagName: "someVersionTag:version", + tagComments: []string{ + "+someVersionTag:version=1.5", + }, + wantValue: &tagValue{ + value: "1.5", + }, + wantMajor: 1, + wantMinor: 5, + wantErr: false, + }, + { + name: "multiple declarations of same tag should return an error", + tagName: "someVersionTag:version", + tagComments: []string{ + "+someVersionTag:version=1.5", + "+someVersionTag:version=v1.7", + }, + wantValue: nil, + wantFatal: true, + }, + { + name: "multiple values on same tag should return an error", + tagName: "someVersionTag:version", + tagComments: []string{ + "+someVersionTag:version=1.5,something", + }, + wantValue: nil, + wantFatal: true, + }, + { + name: "wrong tag major value should return an error", + tagName: "someVersionTag:version", + tagComments: []string{ + "+someVersionTag:version=.5", + }, + wantErr: true, + }, + { + name: "wrong tag minor value should return an error", + tagName: "someVersionTag:version", + tagComments: []string{ + "+someVersionTag:version=1.", + }, + wantErr: true, + }, + { + name: "wrong tag format should return an error", + tagName: "someVersionTag:version", + tagComments: []string{ + "+someVersionTag:version=1.5.7", + }, + wantErr: true, + }, + { + name: "wrong tag major int value should return an error", + tagName: "someVersionTag:version", + tagComments: []string{ + "+someVersionTag:version=blah.5", + }, + wantErr: true, + }, + { + name: "wrong tag minor int value should return an error", + tagName: "someVersionTag:version", + tagComments: []string{ + "+someVersionTag:version=1.blah", + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mockType.SecondClosestCommentLines = tt.tagComments + gotTag, gotMajor, gotMinor, err, fatalErr := safeExtractKubeVersionTag(tt.tagName, mockType) + if (fatalErr != nil) != tt.wantFatal { + t.Errorf("extractKubeVersionTag() fatalErr = %v, wantFatal %v", fatalErr, tt.wantFatal) + return + } + if tt.wantFatal { + return + } + if (err != nil) != tt.wantErr { + t.Errorf("extractKubeVersionTag() error = %v, wantErr %v", err, tt.wantErr) + return + } + if tt.wantErr { + return + } + if !reflect.DeepEqual(gotTag, tt.wantValue) { + t.Errorf("extractKubeVersionTag() got = %v, want %v", gotTag, tt.wantValue) + } + if gotMajor != tt.wantMajor { + t.Errorf("extractKubeVersionTag() got1 = %v, want %v", gotMajor, tt.wantMajor) + } + if gotMinor != tt.wantMinor { + t.Errorf("extractKubeVersionTag() got2 = %v, want %v", gotMinor, tt.wantMinor) + } + }) + } +} + +func customExit(exitCode int) { + panic(strconv.Itoa(exitCode)) +} + +func safeExtractKubeVersionTag(tagName string, t *types.Type) (value *tagValue, major int, minor int, err error, localErr error) { + defer func() { + if e := recover(); e != nil { + localErr = fmt.Errorf("extractKubeVersionTag returned error: %v", e) + } + }() + value, major, minor, err = extractKubeVersionTag(tagName, t) + return +} + +func safeExtractTag(t *testing.T, tagName string, comments []string) (value *tagValue, err error) { + defer func() { + if e := recover(); e != nil { + err = fmt.Errorf("extractTag returned error: %v", e) + } + }() + value = extractTag(tagName, comments) + return +} + +func Test_extractTag(t *testing.T) { + oldKlogOsExit := klog.OsExit + defer func() { + klog.OsExit = oldKlogOsExit + }() + klog.OsExit = customExit + + comments := []string{ + "+variable=7", + "+anotherVariable=8", + "+yetAnotherVariable=9", + "variableWithoutMarker=10", + "+variableWithoutValue", + "+variable=11", + "+multi-valuedVariable=12,13,14", + "+strangeVariable=15,=16", + } + + tests := []struct { + name string + tagComments []string + variableName string + wantError bool + wantValue *tagValue + }{ + { + name: "variable with explicit value", + tagComments: comments, + variableName: "anotherVariable", + wantValue: &tagValue{value: "8"}, + }, + { + name: "variable without explicit value", + tagComments: comments, + variableName: "variableWithoutValue", + wantValue: &tagValue{value: ""}, + }, + { + name: "variable not present in comments", + tagComments: comments, + variableName: "variableOutOfNowhere", + wantValue: nil, + }, + { + name: "variable without marker test", + tagComments: comments, + variableName: "variableWithoutMarker", + wantValue: nil, + }, + { + name: "abort duplicated variable", + tagComments: comments, + variableName: "variable", + wantError: true, + wantValue: nil, + }, + { + name: "abort variable with multiple values", + tagComments: comments, + variableName: "multi-valuedVariable", + wantError: true, + wantValue: nil, + }, + { + name: "this test documents strange behaviour", // TODO: Is this behaviour intended? + tagComments: comments, + variableName: "strangeVariable", + wantValue: &tagValue{value: "15"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotTag, err := safeExtractTag(t, tt.variableName, tt.tagComments) + if (err != nil) != tt.wantError { + t.Errorf("extractTag() err = %v, wantError = %v.", gotTag, tt.wantError) + return + } + if tt.wantError { + return + } + if !reflect.DeepEqual(gotTag, tt.wantValue) { + t.Errorf("extractTag() got = %v, want %v", gotTag, tt.wantValue) + } + }) + } +} + +func Test_extractEnabledTypeTag(t *testing.T) { + someComments := []string{ + "+variable=7", + "+k8s:prerelease-lifecycle-gen=8", + } + moreComments := []string{ + "+yetAnotherVariable=9", + "variableWithoutMarker=10", + "+variableWithoutValue", + "+variable=11", + "+multi-valuedVariable=12,13,14", + } + + tests := []struct { + name string + mockType *types.Type + wantValue *tagValue + }{ + { + name: "desired info in main comments", + mockType: &types.Type{CommentLines: someComments, SecondClosestCommentLines: moreComments}, + wantValue: &tagValue{value: "8"}, + }, + { + name: "secondary comments empty", + mockType: &types.Type{CommentLines: someComments}, + wantValue: &tagValue{value: "8"}, + }, + { + name: "main comments empty", + mockType: &types.Type{SecondClosestCommentLines: someComments}, + wantValue: &tagValue{value: "8"}, + }, + { + name: "lack of desired info, empty secondary comments", + mockType: &types.Type{CommentLines: moreComments}, + wantValue: nil, + }, + { + name: "lack of desired info, empty main comments", + mockType: &types.Type{SecondClosestCommentLines: moreComments}, + wantValue: nil, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + gotTag := extractEnabledTypeTag(tt.mockType) + if !reflect.DeepEqual(gotTag, tt.wantValue) { + t.Errorf("extractEnabledTypeTag() got = %v, want %v", gotTag, tt.wantValue) + } + }) + } +} + +func Test_extractReplacementTag(t *testing.T) { + replacementTag := "+k8s:prerelease-lifecycle-gen:replacement" + tests := []struct { + name string + mainComments []string + secondaryComments []string + wantGroup string + wantVersion string + wantKind string + wantHasReplacement bool + wantErr bool + }{ + { + name: "no replacement tag", + mainComments: []string{"randomText=7"}, + secondaryComments: []string{"importantFlag=8.8.8.8"}, + wantGroup: "", + wantVersion: "", + wantKind: "", + wantHasReplacement: false, + wantErr: false, + }, + { + name: "replacement tag correct", + mainComments: []string{fmt.Sprintf("%v=my_group,v1,KindOf", replacementTag)}, + secondaryComments: []string{}, + wantGroup: "my_group", + wantVersion: "v1", + wantKind: "KindOf", + wantHasReplacement: true, + wantErr: false, + }, + { + name: "correct replacement tag in secondary comments", + mainComments: []string{}, + secondaryComments: []string{fmt.Sprintf("%v=my_group,v1,KindOf", replacementTag)}, + wantGroup: "my_group", + wantVersion: "v1", + wantKind: "KindOf", + wantHasReplacement: true, + wantErr: false, + }, + { + name: "4 values instead of 3", + mainComments: []string{fmt.Sprintf("%v=my_group,v1,KindOf,subKind", replacementTag)}, + secondaryComments: []string{}, + wantGroup: "", + wantVersion: "", + wantKind: "", + wantHasReplacement: false, + wantErr: true, + }, + { + name: "4 values instead of 3 in secondary comments", + mainComments: []string{}, + secondaryComments: []string{fmt.Sprintf("%v=my_group,v1,KindOf,subKind", replacementTag)}, + wantGroup: "", + wantVersion: "", + wantKind: "", + wantHasReplacement: false, + wantErr: true, + }, + { + name: "2 values instead of 3", + mainComments: []string{fmt.Sprintf("%v=my_group,v1", replacementTag)}, + secondaryComments: []string{}, + wantGroup: "", + wantVersion: "", + wantKind: "", + wantHasReplacement: false, + wantErr: true, + }, + { + name: "group name not all upper", + mainComments: []string{fmt.Sprintf("%v=myGroup,v1,KindOf", replacementTag)}, + secondaryComments: []string{}, + wantGroup: "", + wantVersion: "", + wantKind: "", + wantHasReplacement: false, + wantErr: true, + }, + { + name: "version name does not start with v", + mainComments: []string{fmt.Sprintf("%v=my_group,bestVersion,KindOf", replacementTag)}, + secondaryComments: []string{}, + wantGroup: "", + wantVersion: "", + wantKind: "", + wantHasReplacement: false, + wantErr: true, + }, + { + name: "kind name does not start with capital", + mainComments: []string{fmt.Sprintf("%v=my_group,v1,kindOf", replacementTag)}, + secondaryComments: []string{}, + wantGroup: "", + wantVersion: "", + wantKind: "", + wantHasReplacement: false, + wantErr: true, + }, + { + name: "empty group name", // TODO: is it a valid input or a bug? + mainComments: []string{fmt.Sprintf("%v=,v1,KindOf", replacementTag)}, + secondaryComments: []string{}, + wantGroup: "", + wantVersion: "v1", + wantKind: "KindOf", + wantHasReplacement: true, + wantErr: false, + }, + { + name: "empty version", + mainComments: []string{fmt.Sprintf("%v=my_group,,KindOf", replacementTag)}, + secondaryComments: []string{}, + wantGroup: "", + wantVersion: "", + wantKind: "", + wantHasReplacement: false, + wantErr: true, + }, + { + name: "empty kind", + mainComments: []string{fmt.Sprintf("%v=my_group,v1,", replacementTag)}, + secondaryComments: []string{}, + wantGroup: "", + wantVersion: "", + wantKind: "", + wantHasReplacement: false, + wantErr: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + replacementGroup, replacementVersion, replacementKind, hasReplacement, err := extractReplacementTag(&types.Type{ + CommentLines: tt.mainComments, + SecondClosestCommentLines: tt.secondaryComments, + }) + if replacementGroup != tt.wantGroup { + t.Errorf("extractReplacementTag() group got = %v, want %v", replacementGroup, tt.wantGroup) + } + if replacementVersion != tt.wantVersion { + t.Errorf("extractReplacementTag() version got = %v, want %v", replacementVersion, tt.wantVersion) + } + if replacementKind != tt.wantKind { + t.Errorf("extractReplacementTag() kind got = %v, want %v", replacementKind, tt.wantKind) + } + if hasReplacement != tt.wantHasReplacement { + t.Errorf("extractReplacementTag() hasReplacement got = %v, want %v", hasReplacement, tt.wantHasReplacement) + } + if (err != nil) != tt.wantErr { + t.Errorf("extractReplacementTag() err got = %v, want %v", err, tt.wantErr) + } + }) + } +} + +func Test_isAPIType(t *testing.T) { + tests := []struct { + name string + t *types.Type + want bool + }{ + { + name: "private name is not apitype", + want: false, + t: &types.Type{ + Name: types.Name{ + Name: "notpublic", + }, + }, + }, + { + name: "non struct is not apitype", + want: false, + t: &types.Type{ + Name: types.Name{ + Name: "Public", + }, + Kind: types.Slice, + }, + }, + { + name: "contains member type", + want: true, + t: &types.Type{ + Name: types.Name{ + Name: "Public", + }, + Kind: types.Struct, + Members: []types.Member{ + { + Embedded: true, + Name: "TypeMeta", + }, + }, + }, + }, + + { + name: "contains no type", + want: false, + t: &types.Type{ + Name: types.Name{ + Name: "Public", + }, + Kind: types.Struct, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := isAPIType(tt.t); got != tt.want { + t.Errorf("isAPIType() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/code-generator/cmd/register-gen/args/args.go b/code-generator/cmd/register-gen/args/args.go new file mode 100644 index 000000000..cc1fdafc8 --- /dev/null +++ b/code-generator/cmd/register-gen/args/args.go @@ -0,0 +1,50 @@ +/* +Copyright 2018 The Kubernetes 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" +) + +type Args struct { + OutputFile string + GoHeaderFile string +} + +// New returns default arguments for the generator. +func New() *Args { + return &Args{} +} + +// AddFlags add the generator flags to the flag set. +func (args *Args) AddFlags(fs *pflag.FlagSet) { + fs.StringVar(&args.OutputFile, "output-file", "generated.register.go", + "the name of the file to be generated") + fs.StringVar(&args.GoHeaderFile, "go-header-file", "", + "the path to a file containing boilerplate header text; the string \"YEAR\" will be replaced with the current 4-digit year") +} + +// Validate checks the given arguments. +func (args *Args) Validate() error { + if len(args.OutputFile) == 0 { + return fmt.Errorf("output file base name cannot be empty") + } + + return nil +} diff --git a/code-generator/cmd/register-gen/generators/register_external.go b/code-generator/cmd/register-gen/generators/register_external.go new file mode 100644 index 000000000..7eb7793e4 --- /dev/null +++ b/code-generator/cmd/register-gen/generators/register_external.go @@ -0,0 +1,117 @@ +/* +Copyright 2018 The Kubernetes 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" + "sort" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" +) + +type registerExternalGenerator struct { + generator.GoGenerator + outputPackage string + gv clientgentypes.GroupVersion + typesToGenerate []*types.Type + imports namer.ImportTracker +} + +var _ generator.Generator = ®isterExternalGenerator{} + +func (g *registerExternalGenerator) Filter(_ *generator.Context, _ *types.Type) bool { + return false +} + +func (g *registerExternalGenerator) Imports(c *generator.Context) (imports []string) { + return g.imports.ImportLines() +} + +func (g *registerExternalGenerator) Namers(_ *generator.Context) namer.NameSystems { + return namer.NameSystems{ + "raw": namer.NewRawNamer(g.outputPackage, g.imports), + } +} + +func (g *registerExternalGenerator) Finalize(context *generator.Context, w io.Writer) error { + typesToGenerateOnlyNames := make([]string, len(g.typesToGenerate)) + for index, typeToGenerate := range g.typesToGenerate { + typesToGenerateOnlyNames[index] = typeToGenerate.Name.Name + } + + // sort the list of types to register, so that the generator produces stable output + sort.Strings(typesToGenerateOnlyNames) + + sw := generator.NewSnippetWriter(w, context, "$", "$") + m := map[string]interface{}{ + "groupName": g.gv.Group, + "version": g.gv.Version, + "types": typesToGenerateOnlyNames, + "addToGroupVersion": context.Universe.Function(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "AddToGroupVersion"}), + "groupVersion": context.Universe.Type(types.Name{Package: "k8s.io/apimachinery/pkg/apis/meta/v1", Name: "GroupVersion"}), + } + sw.Do(registerExternalTypesTemplate, m) + return sw.Error() +} + +var registerExternalTypesTemplate = ` +// GroupName specifies the group name used to register the objects. +const GroupName = "$.groupName$" + +// GroupVersion specifies the group and the version used to register the objects. +var GroupVersion = $.groupVersion|raw${Group: GroupName, Version: "$.version$"} + +// SchemeGroupVersion is group version used to register these objects +// Deprecated: use GroupVersion instead. +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "$.version$"} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + // Deprecated: use Install instead + AddToScheme = localSchemeBuilder.AddToScheme + Install = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + $range .types -$ + &$.${}, + $end$ + ) + // AddToGroupVersion allows the serialization of client types like ListOptions. + $.addToGroupVersion|raw$(scheme, SchemeGroupVersion) + return nil +} +` diff --git a/code-generator/cmd/register-gen/generators/targets.go b/code-generator/cmd/register-gen/generators/targets.go new file mode 100644 index 000000000..952e276f7 --- /dev/null +++ b/code-generator/cmd/register-gen/generators/targets.go @@ -0,0 +1,139 @@ +/* +Copyright 2018 The Kubernetes 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 ( + "fmt" + "os" + "path" + "strings" + + "k8s.io/klog/v2" + + clientgentypes "k8s.io/code-generator/cmd/client-gen/types" + "k8s.io/code-generator/cmd/register-gen/args" + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" +) + +// NameSystems returns the name system used by the generators in this package. +func NameSystems() namer.NameSystems { + return namer.NameSystems{} +} + +// DefaultNameSystem returns the default name system for ordering the types to be +// processed by the generators in this package. +func DefaultNameSystem() string { + return "public" +} + +// GetTargets makes targets to generate. +func GetTargets(context *generator.Context, args *args.Args) []generator.Target { + boilerplate, err := gengo.GoBoilerplate(args.GoHeaderFile, gengo.StdBuildTag, gengo.StdGeneratedBy) + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + targets := []generator.Target{} + for _, input := range context.Inputs { + pkg := context.Universe.Package(input) + internal, err := isInternal(pkg) + if err != nil { + klog.V(5).Infof("skipping the generation of %s file, due to err %v", args.OutputFile, err) + continue + } + if internal { + klog.V(5).Infof("skipping the generation of %s file because %s package contains internal types, note that internal types don't have \"json\" tags", args.OutputFile, pkg.Name) + continue + } + registerFileName := "register.go" + searchPath := path.Join(pkg.Dir, registerFileName) + if _, err := os.Stat(path.Join(searchPath)); err == nil { + klog.V(5).Infof("skipping the generation of %s file because %s already exists in the path %s", args.OutputFile, registerFileName, searchPath) + continue + } else if err != nil && !os.IsNotExist(err) { + klog.Fatalf("an error %v has occurred while checking if %s exists", err, registerFileName) + } + + gv := clientgentypes.GroupVersion{} + { + pathParts := strings.Split(pkg.Path, "/") + if len(pathParts) < 2 { + klog.Errorf("the path of the package must contain the group name and the version, path = %s", pkg.Path) + continue + } + gv.Group = clientgentypes.Group(pathParts[len(pathParts)-2]) + gv.Version = clientgentypes.Version(pathParts[len(pathParts)-1]) + + // if there is a comment of the form "// +groupName=somegroup" or "// +groupName=somegroup.foo.bar.io", + // extract the fully qualified API group name from it and overwrite the group inferred from the package path + if override := gengo.ExtractCommentTags("+", pkg.Comments)["groupName"]; override != nil { + groupName := override[0] + klog.V(5).Infof("overriding the group name with = %s", groupName) + gv.Group = clientgentypes.Group(groupName) + } + } + + typesToRegister := []*types.Type{} + for _, t := range pkg.Types { + klog.V(5).Infof("considering type = %s", t.Name.String()) + for _, typeMember := range t.Members { + if typeMember.Name == "TypeMeta" && typeMember.Embedded { + typesToRegister = append(typesToRegister, t) + } + } + } + + targets = append(targets, + &generator.SimpleTarget{ + PkgName: pkg.Name, + PkgPath: pkg.Path, // output to same pkg as input + PkgDir: pkg.Dir, // output to same pkg as input + HeaderComment: boilerplate, + GeneratorsFunc: func(c *generator.Context) (generators []generator.Generator) { + return []generator.Generator{ + ®isterExternalGenerator{ + GoGenerator: generator.GoGenerator{ + OutputFilename: args.OutputFile, + }, + gv: gv, + typesToGenerate: typesToRegister, + outputPackage: pkg.Path, + imports: generator.NewImportTrackerForPackage(pkg.Path), + }, + } + }, + }) + } + + return targets +} + +// isInternal determines whether the given package +// contains the internal types or not +func isInternal(p *types.Package) (bool, error) { + for _, t := range p.Types { + for _, member := range t.Members { + if member.Name == "TypeMeta" { + return !strings.Contains(member.Tags, "json"), nil + } + } + } + return false, fmt.Errorf("unable to find TypeMeta for any types in package %s", p.Path) +} diff --git a/code-generator/cmd/register-gen/main.go b/code-generator/cmd/register-gen/main.go new file mode 100644 index 000000000..ac28f87fb --- /dev/null +++ b/code-generator/cmd/register-gen/main.go @@ -0,0 +1,56 @@ +/* +Copyright 2018 The Kubernetes 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" + + "github.com/spf13/pflag" + "k8s.io/code-generator/cmd/register-gen/args" + "k8s.io/code-generator/cmd/register-gen/generators" + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/generator" + "k8s.io/klog/v2" +) + +func main() { + klog.InitFlags(nil) + args := args.New() + args.AddFlags(pflag.CommandLine) + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + + pflag.Parse() + if err := args.Validate(); err != nil { + klog.Fatalf("Error: %v", err) + } + + myTargets := func(context *generator.Context) []generator.Target { + return generators.GetTargets(context, args) + } + + if err := gengo.Execute( + generators.NameSystems(), + generators.DefaultNameSystem(), + myTargets, + gengo.StdBuildTag, + pflag.Args(), + ); err != nil { + klog.Fatalf("Error: %v", err) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/code-generator/code-of-conduct.md b/code-generator/code-of-conduct.md new file mode 100644 index 000000000..0d15c00cf --- /dev/null +++ b/code-generator/code-of-conduct.md @@ -0,0 +1,3 @@ +# Kubernetes Community Code of Conduct + +Please refer to our [Kubernetes Community Code of Conduct](https://git.k8s.io/community/code-of-conduct.md) diff --git a/code-generator/doc.go b/code-generator/doc.go new file mode 100644 index 000000000..fd8673069 --- /dev/null +++ b/code-generator/doc.go @@ -0,0 +1,17 @@ +/* +Copyright 2021 The Kubernetes 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 codegenerator // import "k8s.io/code-generator" diff --git a/code-generator/examples/.gitignore b/code-generator/examples/.gitignore new file mode 100644 index 000000000..8ae0c29ad --- /dev/null +++ b/code-generator/examples/.gitignore @@ -0,0 +1,2 @@ +# avoid constant churn as this file is not kept in sync with the root +go.work.sum diff --git a/code-generator/examples/HyphenGroup/apis/example/v1/doc.go b/code-generator/examples/HyphenGroup/apis/example/v1/doc.go new file mode 100644 index 000000000..9bf8515c5 --- /dev/null +++ b/code-generator/examples/HyphenGroup/apis/example/v1/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2019 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:defaulter-gen=TypeMeta +// +groupName=example-group.hyphens.code-generator.k8s.io +// +groupGoName=ExampleGroup +package v1 // import "k8s.io/code-generator/examples/HyphenGroup/apis/example/v1" diff --git a/code-generator/examples/HyphenGroup/apis/example/v1/register.go b/code-generator/examples/HyphenGroup/apis/example/v1/register.go new file mode 100644 index 000000000..3c837ae73 --- /dev/null +++ b/code-generator/examples/HyphenGroup/apis/example/v1/register.go @@ -0,0 +1,59 @@ +/* +Copyright 2019 The Kubernetes 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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example-group.hyphens.code-generator.k8s.io", Version: "v1"} + +var ( + // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion, + &metav1.Status{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/code-generator/examples/HyphenGroup/apis/example/v1/types.go b/code-generator/examples/HyphenGroup/apis/example/v1/types.go new file mode 100644 index 000000000..b8c7f8233 --- /dev/null +++ b/code-generator/examples/HyphenGroup/apis/example/v1/types.go @@ -0,0 +1,74 @@ +/* +Copyright 2019 The Kubernetes 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 v1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status TestTypeStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []TestType `json:"items"` +} + +type TestTypeStatus struct { + Blah string `json:"blah"` +} + +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type ClusterTestTypeList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []ClusterTestType `json:"items"` +} + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient:method=GetScale,verb=get,subresource=scale,result=k8s.io/api/autoscaling/v1.Scale +// +genclient:method=UpdateScale,verb=update,subresource=scale,input=k8s.io/api/autoscaling/v1.Scale,result=k8s.io/api/autoscaling/v1.Scale + +type ClusterTestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status ClusterTestTypeStatus `json:"status,omitempty"` +} + +type ClusterTestTypeStatus struct { + Blah string `json:"blah"` +} diff --git a/code-generator/examples/HyphenGroup/apis/example/v1/zz_generated.deepcopy.go b/code-generator/examples/HyphenGroup/apis/example/v1/zz_generated.deepcopy.go new file mode 100644 index 000000000..5eee47016 --- /dev/null +++ b/code-generator/examples/HyphenGroup/apis/example/v1/zz_generated.deepcopy.go @@ -0,0 +1,178 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestType) DeepCopyInto(out *ClusterTestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestType. +func (in *ClusterTestType) DeepCopy() *ClusterTestType { + if in == nil { + return nil + } + out := new(ClusterTestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterTestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestTypeList) DeepCopyInto(out *ClusterTestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ClusterTestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestTypeList. +func (in *ClusterTestTypeList) DeepCopy() *ClusterTestTypeList { + if in == nil { + return nil + } + out := new(ClusterTestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterTestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestTypeStatus) DeepCopyInto(out *ClusterTestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestTypeStatus. +func (in *ClusterTestTypeStatus) DeepCopy() *ClusterTestTypeStatus { + if in == nil { + return nil + } + out := new(ClusterTestTypeStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/examples/HyphenGroup/apis/example/v1/zz_generated.defaults.go b/code-generator/examples/HyphenGroup/apis/example/v1/zz_generated.defaults.go new file mode 100644 index 000000000..dac177e93 --- /dev/null +++ b/code-generator/examples/HyphenGroup/apis/example/v1/zz_generated.defaults.go @@ -0,0 +1,33 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/code-generator/examples/HyphenGroup/applyconfiguration/example/v1/clustertesttype.go b/code-generator/examples/HyphenGroup/applyconfiguration/example/v1/clustertesttype.go new file mode 100644 index 000000000..06c539052 --- /dev/null +++ b/code-generator/examples/HyphenGroup/applyconfiguration/example/v1/clustertesttype.go @@ -0,0 +1,215 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +import ( + apismetav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + metav1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// ClusterTestTypeApplyConfiguration represents a declarative configuration of the ClusterTestType type for use +// with apply. +type ClusterTestTypeApplyConfiguration struct { + metav1.TypeMetaApplyConfiguration `json:",inline"` + *metav1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Status *ClusterTestTypeStatusApplyConfiguration `json:"status,omitempty"` +} + +// ClusterTestType constructs a declarative configuration of the ClusterTestType type for use with +// apply. +func ClusterTestType(name string) *ClusterTestTypeApplyConfiguration { + b := &ClusterTestTypeApplyConfiguration{} + b.WithName(name) + b.WithKind("ClusterTestType") + b.WithAPIVersion("example-group.hyphens.code-generator.k8s.io/v1") + return b +} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithKind(value string) *ClusterTestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithAPIVersion(value string) *ClusterTestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithName(value string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithGenerateName(value string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithNamespace(value string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithUID(value types.UID) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithResourceVersion(value string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithGeneration(value int64) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithCreationTimestamp(value apismetav1.Time) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithDeletionTimestamp(value apismetav1.Time) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *ClusterTestTypeApplyConfiguration) WithLabels(entries map[string]string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *ClusterTestTypeApplyConfiguration) WithAnnotations(entries map[string]string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *ClusterTestTypeApplyConfiguration) WithOwnerReferences(values ...*metav1.OwnerReferenceApplyConfiguration) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *ClusterTestTypeApplyConfiguration) WithFinalizers(values ...string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *ClusterTestTypeApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &metav1.ObjectMetaApplyConfiguration{} + } +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithStatus(value *ClusterTestTypeStatusApplyConfiguration) *ClusterTestTypeApplyConfiguration { + b.Status = value + return b +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *ClusterTestTypeApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} diff --git a/code-generator/examples/HyphenGroup/applyconfiguration/example/v1/clustertesttypestatus.go b/code-generator/examples/HyphenGroup/applyconfiguration/example/v1/clustertesttypestatus.go new file mode 100644 index 000000000..c2ccfa581 --- /dev/null +++ b/code-generator/examples/HyphenGroup/applyconfiguration/example/v1/clustertesttypestatus.go @@ -0,0 +1,39 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// ClusterTestTypeStatusApplyConfiguration represents a declarative configuration of the ClusterTestTypeStatus type for use +// with apply. +type ClusterTestTypeStatusApplyConfiguration struct { + Blah *string `json:"blah,omitempty"` +} + +// ClusterTestTypeStatusApplyConfiguration constructs a declarative configuration of the ClusterTestTypeStatus type for use with +// apply. +func ClusterTestTypeStatus() *ClusterTestTypeStatusApplyConfiguration { + return &ClusterTestTypeStatusApplyConfiguration{} +} + +// WithBlah sets the Blah field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Blah field is set to the value of the last call. +func (b *ClusterTestTypeStatusApplyConfiguration) WithBlah(value string) *ClusterTestTypeStatusApplyConfiguration { + b.Blah = &value + return b +} diff --git a/code-generator/examples/HyphenGroup/applyconfiguration/example/v1/testtype.go b/code-generator/examples/HyphenGroup/applyconfiguration/example/v1/testtype.go new file mode 100644 index 000000000..3481b7866 --- /dev/null +++ b/code-generator/examples/HyphenGroup/applyconfiguration/example/v1/testtype.go @@ -0,0 +1,216 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +import ( + apismetav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + metav1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// TestTypeApplyConfiguration represents a declarative configuration of the TestType type for use +// with apply. +type TestTypeApplyConfiguration struct { + metav1.TypeMetaApplyConfiguration `json:",inline"` + *metav1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Status *TestTypeStatusApplyConfiguration `json:"status,omitempty"` +} + +// TestType constructs a declarative configuration of the TestType type for use with +// apply. +func TestType(name, namespace string) *TestTypeApplyConfiguration { + b := &TestTypeApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("TestType") + b.WithAPIVersion("example-group.hyphens.code-generator.k8s.io/v1") + return b +} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithKind(value string) *TestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithAPIVersion(value string) *TestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithName(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithGenerateName(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithNamespace(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithUID(value types.UID) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithResourceVersion(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithGeneration(value int64) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithCreationTimestamp(value apismetav1.Time) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithDeletionTimestamp(value apismetav1.Time) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *TestTypeApplyConfiguration) WithLabels(entries map[string]string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *TestTypeApplyConfiguration) WithAnnotations(entries map[string]string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *TestTypeApplyConfiguration) WithOwnerReferences(values ...*metav1.OwnerReferenceApplyConfiguration) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *TestTypeApplyConfiguration) WithFinalizers(values ...string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *TestTypeApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &metav1.ObjectMetaApplyConfiguration{} + } +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithStatus(value *TestTypeStatusApplyConfiguration) *TestTypeApplyConfiguration { + b.Status = value + return b +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *TestTypeApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} diff --git a/code-generator/examples/HyphenGroup/applyconfiguration/example/v1/testtypestatus.go b/code-generator/examples/HyphenGroup/applyconfiguration/example/v1/testtypestatus.go new file mode 100644 index 000000000..246b2ee18 --- /dev/null +++ b/code-generator/examples/HyphenGroup/applyconfiguration/example/v1/testtypestatus.go @@ -0,0 +1,39 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// TestTypeStatusApplyConfiguration represents a declarative configuration of the TestTypeStatus type for use +// with apply. +type TestTypeStatusApplyConfiguration struct { + Blah *string `json:"blah,omitempty"` +} + +// TestTypeStatusApplyConfiguration constructs a declarative configuration of the TestTypeStatus type for use with +// apply. +func TestTypeStatus() *TestTypeStatusApplyConfiguration { + return &TestTypeStatusApplyConfiguration{} +} + +// WithBlah sets the Blah field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Blah field is set to the value of the last call. +func (b *TestTypeStatusApplyConfiguration) WithBlah(value string) *TestTypeStatusApplyConfiguration { + b.Blah = &value + return b +} diff --git a/code-generator/examples/HyphenGroup/applyconfiguration/internal/internal.go b/code-generator/examples/HyphenGroup/applyconfiguration/internal/internal.go new file mode 100644 index 000000000..1064e227e --- /dev/null +++ b/code-generator/examples/HyphenGroup/applyconfiguration/internal/internal.go @@ -0,0 +1,62 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package internal + +import ( + fmt "fmt" + sync "sync" + + typed "sigs.k8s.io/structured-merge-diff/v4/typed" +) + +func Parser() *typed.Parser { + parserOnce.Do(func() { + var err error + parser, err = typed.NewParser(schemaYAML) + if err != nil { + panic(fmt.Sprintf("Failed to parse schema: %v", err)) + } + }) + return parser +} + +var parserOnce sync.Once +var parser *typed.Parser +var schemaYAML = typed.YAMLObject(`types: +- name: __untyped_atomic_ + scalar: untyped + list: + elementType: + namedType: __untyped_atomic_ + elementRelationship: atomic + map: + elementType: + namedType: __untyped_atomic_ + elementRelationship: atomic +- name: __untyped_deduced_ + scalar: untyped + list: + elementType: + namedType: __untyped_atomic_ + elementRelationship: atomic + map: + elementType: + namedType: __untyped_deduced_ + elementRelationship: separable +`) diff --git a/code-generator/examples/HyphenGroup/applyconfiguration/utils.go b/code-generator/examples/HyphenGroup/applyconfiguration/utils.go new file mode 100644 index 000000000..ed9060269 --- /dev/null +++ b/code-generator/examples/HyphenGroup/applyconfiguration/utils.go @@ -0,0 +1,50 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package applyconfiguration + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/HyphenGroup/apis/example/v1" + examplev1 "k8s.io/code-generator/examples/HyphenGroup/applyconfiguration/example/v1" + internal "k8s.io/code-generator/examples/HyphenGroup/applyconfiguration/internal" +) + +// ForKind returns an apply configuration type for the given GroupVersionKind, or nil if no +// apply configuration type exists for the given GroupVersionKind. +func ForKind(kind schema.GroupVersionKind) interface{} { + switch kind { + // Group=example-group.hyphens.code-generator.k8s.io, Version=v1 + case v1.SchemeGroupVersion.WithKind("ClusterTestType"): + return &examplev1.ClusterTestTypeApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("ClusterTestTypeStatus"): + return &examplev1.ClusterTestTypeStatusApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("TestType"): + return &examplev1.TestTypeApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("TestTypeStatus"): + return &examplev1.TestTypeStatusApplyConfiguration{} + + } + return nil +} + +func NewTypeConverter(scheme *runtime.Scheme) *testing.TypeConverter { + return &testing.TypeConverter{Scheme: scheme, TypeResolver: internal.Parser()} +} diff --git a/pkg/generated/clientset/versioned/clientset.go b/code-generator/examples/HyphenGroup/clientset/versioned/clientset.go similarity index 82% rename from pkg/generated/clientset/versioned/clientset.go rename to code-generator/examples/HyphenGroup/clientset/versioned/clientset.go index 6362e3e2b..8ac4bb86f 100644 --- a/pkg/generated/clientset/versioned/clientset.go +++ b/code-generator/examples/HyphenGroup/clientset/versioned/clientset.go @@ -25,23 +25,23 @@ import ( discovery "k8s.io/client-go/discovery" rest "k8s.io/client-go/rest" flowcontrol "k8s.io/client-go/util/flowcontrol" - samplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1" + examplegroupv1 "k8s.io/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1" ) type Interface interface { Discovery() discovery.DiscoveryInterface - SamplecontrollerV1alpha1() samplecontrollerv1alpha1.SamplecontrollerV1alpha1Interface + ExampleGroupV1() examplegroupv1.ExampleGroupV1Interface } // Clientset contains the clients for groups. type Clientset struct { *discovery.DiscoveryClient - samplecontrollerV1alpha1 *samplecontrollerv1alpha1.SamplecontrollerV1alpha1Client + exampleGroupV1 *examplegroupv1.ExampleGroupV1Client } -// SamplecontrollerV1alpha1 retrieves the SamplecontrollerV1alpha1Client -func (c *Clientset) SamplecontrollerV1alpha1() samplecontrollerv1alpha1.SamplecontrollerV1alpha1Interface { - return c.samplecontrollerV1alpha1 +// ExampleGroupV1 retrieves the ExampleGroupV1Client +func (c *Clientset) ExampleGroupV1() examplegroupv1.ExampleGroupV1Interface { + return c.exampleGroupV1 } // Discovery retrieves the DiscoveryClient @@ -88,7 +88,7 @@ func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, var cs Clientset var err error - cs.samplecontrollerV1alpha1, err = samplecontrollerv1alpha1.NewForConfigAndClient(&configShallowCopy, httpClient) + cs.exampleGroupV1, err = examplegroupv1.NewForConfigAndClient(&configShallowCopy, httpClient) if err != nil { return nil, err } @@ -113,7 +113,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { // New creates a new Clientset for the given RESTClient. func New(c rest.Interface) *Clientset { var cs Clientset - cs.samplecontrollerV1alpha1 = samplecontrollerv1alpha1.New(c) + cs.exampleGroupV1 = examplegroupv1.New(c) cs.DiscoveryClient = discovery.NewDiscoveryClient(c) return &cs diff --git a/code-generator/examples/HyphenGroup/clientset/versioned/fake/clientset_generated.go b/code-generator/examples/HyphenGroup/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 000000000..f7d91b9fc --- /dev/null +++ b/code-generator/examples/HyphenGroup/clientset/versioned/fake/clientset_generated.go @@ -0,0 +1,122 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" + applyconfiguration "k8s.io/code-generator/examples/HyphenGroup/applyconfiguration" + clientset "k8s.io/code-generator/examples/HyphenGroup/clientset/versioned" + examplegroupv1 "k8s.io/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1" + fakeexamplegroupv1 "k8s.io/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/fake" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any field management, validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +// +// DEPRECATED: NewClientset replaces this with support for field management, which significantly improves +// server side apply testing. NewClientset is only available when apply configurations are generated (e.g. +// via --with-applyconfig). +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery + tracker testing.ObjectTracker +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +func (c *Clientset) Tracker() testing.ObjectTracker { + return c.tracker +} + +// NewClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewClientset(objects ...runtime.Object) *Clientset { + o := testing.NewFieldManagedObjectTracker( + scheme, + codecs.UniversalDecoder(), + applyconfiguration.NewTypeConverter(scheme), + ) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +var ( + _ clientset.Interface = &Clientset{} + _ testing.FakeClient = &Clientset{} +) + +// ExampleGroupV1 retrieves the ExampleGroupV1Client +func (c *Clientset) ExampleGroupV1() examplegroupv1.ExampleGroupV1Interface { + return &fakeexamplegroupv1.FakeExampleGroupV1{Fake: &c.Fake} +} diff --git a/pkg/generated/clientset/versioned/fake/doc.go b/code-generator/examples/HyphenGroup/clientset/versioned/fake/doc.go similarity index 100% rename from pkg/generated/clientset/versioned/fake/doc.go rename to code-generator/examples/HyphenGroup/clientset/versioned/fake/doc.go diff --git a/pkg/generated/clientset/versioned/fake/register.go b/code-generator/examples/HyphenGroup/clientset/versioned/fake/register.go similarity index 93% rename from pkg/generated/clientset/versioned/fake/register.go rename to code-generator/examples/HyphenGroup/clientset/versioned/fake/register.go index 74013e464..3350b2ded 100644 --- a/pkg/generated/clientset/versioned/fake/register.go +++ b/code-generator/examples/HyphenGroup/clientset/versioned/fake/register.go @@ -24,14 +24,14 @@ import ( schema "k8s.io/apimachinery/pkg/runtime/schema" serializer "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" - samplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1" + examplegroupv1 "k8s.io/code-generator/examples/HyphenGroup/apis/example/v1" ) var scheme = runtime.NewScheme() var codecs = serializer.NewCodecFactory(scheme) var localSchemeBuilder = runtime.SchemeBuilder{ - samplecontrollerv1alpha1.AddToScheme, + examplegroupv1.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/pkg/generated/clientset/versioned/scheme/doc.go b/code-generator/examples/HyphenGroup/clientset/versioned/scheme/doc.go similarity index 100% rename from pkg/generated/clientset/versioned/scheme/doc.go rename to code-generator/examples/HyphenGroup/clientset/versioned/scheme/doc.go diff --git a/pkg/generated/clientset/versioned/scheme/register.go b/code-generator/examples/HyphenGroup/clientset/versioned/scheme/register.go similarity index 93% rename from pkg/generated/clientset/versioned/scheme/register.go rename to code-generator/examples/HyphenGroup/clientset/versioned/scheme/register.go index c3378226d..066b540ce 100644 --- a/pkg/generated/clientset/versioned/scheme/register.go +++ b/code-generator/examples/HyphenGroup/clientset/versioned/scheme/register.go @@ -24,14 +24,14 @@ import ( schema "k8s.io/apimachinery/pkg/runtime/schema" serializer "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" - samplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1" + examplegroupv1 "k8s.io/code-generator/examples/HyphenGroup/apis/example/v1" ) var Scheme = runtime.NewScheme() var Codecs = serializer.NewCodecFactory(Scheme) var ParameterCodec = runtime.NewParameterCodec(Scheme) var localSchemeBuilder = runtime.SchemeBuilder{ - samplecontrollerv1alpha1.AddToScheme, + examplegroupv1.AddToScheme, } // AddToScheme adds all types of this clientset into the given scheme. This allows composition diff --git a/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/clustertesttype.go b/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/clustertesttype.go new file mode 100644 index 000000000..fe88fd874 --- /dev/null +++ b/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/clustertesttype.go @@ -0,0 +1,104 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + + autoscalingv1 "k8s.io/api/autoscaling/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + examplev1 "k8s.io/code-generator/examples/HyphenGroup/apis/example/v1" + applyconfigurationexamplev1 "k8s.io/code-generator/examples/HyphenGroup/applyconfiguration/example/v1" + scheme "k8s.io/code-generator/examples/HyphenGroup/clientset/versioned/scheme" +) + +// ClusterTestTypesGetter has a method to return a ClusterTestTypeInterface. +// A group's client should implement this interface. +type ClusterTestTypesGetter interface { + ClusterTestTypes() ClusterTestTypeInterface +} + +// ClusterTestTypeInterface has methods to work with ClusterTestType resources. +type ClusterTestTypeInterface interface { + Create(ctx context.Context, clusterTestType *examplev1.ClusterTestType, opts metav1.CreateOptions) (*examplev1.ClusterTestType, error) + Update(ctx context.Context, clusterTestType *examplev1.ClusterTestType, opts metav1.UpdateOptions) (*examplev1.ClusterTestType, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, clusterTestType *examplev1.ClusterTestType, opts metav1.UpdateOptions) (*examplev1.ClusterTestType, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*examplev1.ClusterTestType, error) + List(ctx context.Context, opts metav1.ListOptions) (*examplev1.ClusterTestTypeList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *examplev1.ClusterTestType, err error) + Apply(ctx context.Context, clusterTestType *applyconfigurationexamplev1.ClusterTestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *examplev1.ClusterTestType, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, clusterTestType *applyconfigurationexamplev1.ClusterTestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *examplev1.ClusterTestType, err error) + GetScale(ctx context.Context, clusterTestTypeName string, options metav1.GetOptions) (*autoscalingv1.Scale, error) + UpdateScale(ctx context.Context, clusterTestTypeName string, scale *autoscalingv1.Scale, opts metav1.UpdateOptions) (*autoscalingv1.Scale, error) + + ClusterTestTypeExpansion +} + +// clusterTestTypes implements ClusterTestTypeInterface +type clusterTestTypes struct { + *gentype.ClientWithListAndApply[*examplev1.ClusterTestType, *examplev1.ClusterTestTypeList, *applyconfigurationexamplev1.ClusterTestTypeApplyConfiguration] +} + +// newClusterTestTypes returns a ClusterTestTypes +func newClusterTestTypes(c *ExampleGroupV1Client) *clusterTestTypes { + return &clusterTestTypes{ + gentype.NewClientWithListAndApply[*examplev1.ClusterTestType, *examplev1.ClusterTestTypeList, *applyconfigurationexamplev1.ClusterTestTypeApplyConfiguration]( + "clustertesttypes", + c.RESTClient(), + scheme.ParameterCodec, + "", + func() *examplev1.ClusterTestType { return &examplev1.ClusterTestType{} }, + func() *examplev1.ClusterTestTypeList { return &examplev1.ClusterTestTypeList{} }), + } +} + +// GetScale takes name of the clusterTestType, and returns the corresponding autoscalingv1.Scale object, and an error if there is any. +func (c *clusterTestTypes) GetScale(ctx context.Context, clusterTestTypeName string, options metav1.GetOptions) (result *autoscalingv1.Scale, err error) { + result = &autoscalingv1.Scale{} + err = c.GetClient().Get(). + Resource("clustertesttypes"). + Name(clusterTestTypeName). + SubResource("scale"). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *clusterTestTypes) UpdateScale(ctx context.Context, clusterTestTypeName string, scale *autoscalingv1.Scale, opts metav1.UpdateOptions) (result *autoscalingv1.Scale, err error) { + result = &autoscalingv1.Scale{} + err = c.GetClient().Put(). + Resource("clustertesttypes"). + Name(clusterTestTypeName). + SubResource("scale"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(scale). + Do(ctx). + Into(result) + return +} diff --git a/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/doc.go b/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/doc.go similarity index 97% rename from pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/doc.go rename to code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/doc.go index df51baa4d..3af5d054f 100644 --- a/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/doc.go +++ b/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/doc.go @@ -17,4 +17,4 @@ limitations under the License. // Code generated by client-gen. DO NOT EDIT. // This package has the automatically generated typed clients. -package v1alpha1 +package v1 diff --git a/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/samplecontroller_client.go b/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/example_client.go similarity index 58% rename from pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/samplecontroller_client.go rename to code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/example_client.go index 68b977746..c10c0a56b 100644 --- a/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/samplecontroller_client.go +++ b/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/example_client.go @@ -16,34 +16,39 @@ limitations under the License. // Code generated by client-gen. DO NOT EDIT. -package v1alpha1 +package v1 import ( http "net/http" rest "k8s.io/client-go/rest" - samplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1" - scheme "k8s.io/sample-controller/pkg/generated/clientset/versioned/scheme" + examplev1 "k8s.io/code-generator/examples/HyphenGroup/apis/example/v1" + scheme "k8s.io/code-generator/examples/HyphenGroup/clientset/versioned/scheme" ) -type SamplecontrollerV1alpha1Interface interface { +type ExampleGroupV1Interface interface { RESTClient() rest.Interface - FoosGetter + ClusterTestTypesGetter + TestTypesGetter } -// SamplecontrollerV1alpha1Client is used to interact with features provided by the samplecontroller.k8s.io group. -type SamplecontrollerV1alpha1Client struct { +// ExampleGroupV1Client is used to interact with features provided by the example-group.hyphens.code-generator.k8s.io group. +type ExampleGroupV1Client struct { restClient rest.Interface } -func (c *SamplecontrollerV1alpha1Client) Foos(namespace string) FooInterface { - return newFoos(c, namespace) +func (c *ExampleGroupV1Client) ClusterTestTypes() ClusterTestTypeInterface { + return newClusterTestTypes(c) } -// NewForConfig creates a new SamplecontrollerV1alpha1Client for the given config. +func (c *ExampleGroupV1Client) TestTypes(namespace string) TestTypeInterface { + return newTestTypes(c, namespace) +} + +// NewForConfig creates a new ExampleGroupV1Client for the given config. // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), // where httpClient was generated with rest.HTTPClientFor(c). -func NewForConfig(c *rest.Config) (*SamplecontrollerV1alpha1Client, error) { +func NewForConfig(c *rest.Config) (*ExampleGroupV1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err @@ -55,9 +60,9 @@ func NewForConfig(c *rest.Config) (*SamplecontrollerV1alpha1Client, error) { return NewForConfigAndClient(&config, httpClient) } -// NewForConfigAndClient creates a new SamplecontrollerV1alpha1Client for the given config and http client. +// NewForConfigAndClient creates a new ExampleGroupV1Client for the given config and http client. // Note the http client provided takes precedence over the configured transport values. -func NewForConfigAndClient(c *rest.Config, h *http.Client) (*SamplecontrollerV1alpha1Client, error) { +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*ExampleGroupV1Client, error) { config := *c if err := setConfigDefaults(&config); err != nil { return nil, err @@ -66,12 +71,12 @@ func NewForConfigAndClient(c *rest.Config, h *http.Client) (*SamplecontrollerV1a if err != nil { return nil, err } - return &SamplecontrollerV1alpha1Client{client}, nil + return &ExampleGroupV1Client{client}, nil } -// NewForConfigOrDie creates a new SamplecontrollerV1alpha1Client for the given config and +// NewForConfigOrDie creates a new ExampleGroupV1Client for the given config and // panics if there is an error in the config. -func NewForConfigOrDie(c *rest.Config) *SamplecontrollerV1alpha1Client { +func NewForConfigOrDie(c *rest.Config) *ExampleGroupV1Client { client, err := NewForConfig(c) if err != nil { panic(err) @@ -79,13 +84,13 @@ func NewForConfigOrDie(c *rest.Config) *SamplecontrollerV1alpha1Client { return client } -// New creates a new SamplecontrollerV1alpha1Client for the given RESTClient. -func New(c rest.Interface) *SamplecontrollerV1alpha1Client { - return &SamplecontrollerV1alpha1Client{c} +// New creates a new ExampleGroupV1Client for the given RESTClient. +func New(c rest.Interface) *ExampleGroupV1Client { + return &ExampleGroupV1Client{c} } func setConfigDefaults(config *rest.Config) error { - gv := samplecontrollerv1alpha1.SchemeGroupVersion + gv := examplev1.SchemeGroupVersion config.GroupVersion = &gv config.APIPath = "/apis" config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() @@ -99,7 +104,7 @@ func setConfigDefaults(config *rest.Config) error { // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. -func (c *SamplecontrollerV1alpha1Client) RESTClient() rest.Interface { +func (c *ExampleGroupV1Client) RESTClient() rest.Interface { if c == nil { return nil } diff --git a/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/fake/doc.go b/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/fake/doc.go similarity index 100% rename from pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/fake/doc.go rename to code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/fake/doc.go diff --git a/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go b/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go new file mode 100644 index 000000000..a2cbe609b --- /dev/null +++ b/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go @@ -0,0 +1,209 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + json "encoding/json" + fmt "fmt" + + autoscalingv1 "k8s.io/api/autoscaling/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/HyphenGroup/apis/example/v1" + examplev1 "k8s.io/code-generator/examples/HyphenGroup/applyconfiguration/example/v1" +) + +// FakeClusterTestTypes implements ClusterTestTypeInterface +type FakeClusterTestTypes struct { + Fake *FakeExampleGroupV1 +} + +var clustertesttypesResource = v1.SchemeGroupVersion.WithResource("clustertesttypes") + +var clustertesttypesKind = v1.SchemeGroupVersion.WithKind("ClusterTestType") + +// Get takes name of the clusterTestType, and returns the corresponding clusterTestType object, and an error if there is any. +func (c *FakeClusterTestTypes) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootGetActionWithOptions(clustertesttypesResource, name, options), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// List takes label and field selectors, and returns the list of ClusterTestTypes that match those selectors. +func (c *FakeClusterTestTypes) List(ctx context.Context, opts metav1.ListOptions) (result *v1.ClusterTestTypeList, err error) { + emptyResult := &v1.ClusterTestTypeList{} + obj, err := c.Fake. + Invokes(testing.NewRootListActionWithOptions(clustertesttypesResource, clustertesttypesKind, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1.ClusterTestTypeList{ListMeta: obj.(*v1.ClusterTestTypeList).ListMeta} + for _, item := range obj.(*v1.ClusterTestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested clusterTestTypes. +func (c *FakeClusterTestTypes) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchActionWithOptions(clustertesttypesResource, opts)) +} + +// Create takes the representation of a clusterTestType and creates it. Returns the server's representation of the clusterTestType, and an error, if there is any. +func (c *FakeClusterTestTypes) Create(ctx context.Context, clusterTestType *v1.ClusterTestType, opts metav1.CreateOptions) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootCreateActionWithOptions(clustertesttypesResource, clusterTestType, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// Update takes the representation of a clusterTestType and updates it. Returns the server's representation of the clusterTestType, and an error, if there is any. +func (c *FakeClusterTestTypes) Update(ctx context.Context, clusterTestType *v1.ClusterTestType, opts metav1.UpdateOptions) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootUpdateActionWithOptions(clustertesttypesResource, clusterTestType, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeClusterTestTypes) UpdateStatus(ctx context.Context, clusterTestType *v1.ClusterTestType, opts metav1.UpdateOptions) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceActionWithOptions(clustertesttypesResource, "status", clusterTestType, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// Delete takes name of the clusterTestType and deletes it. Returns an error if one occurs. +func (c *FakeClusterTestTypes) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(clustertesttypesResource, name, opts), &v1.ClusterTestType{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeClusterTestTypes) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + action := testing.NewRootDeleteCollectionActionWithOptions(clustertesttypesResource, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1.ClusterTestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched clusterTestType. +func (c *FakeClusterTestTypes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clustertesttypesResource, name, pt, data, opts, subresources...), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied clusterTestType. +func (c *FakeClusterTestTypes) Apply(ctx context.Context, clusterTestType *examplev1.ClusterTestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.ClusterTestType, err error) { + if clusterTestType == nil { + return nil, fmt.Errorf("clusterTestType provided to Apply must not be nil") + } + data, err := json.Marshal(clusterTestType) + if err != nil { + return nil, err + } + name := clusterTestType.Name + if name == nil { + return nil, fmt.Errorf("clusterTestType.Name must be provided to Apply") + } + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clustertesttypesResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeClusterTestTypes) ApplyStatus(ctx context.Context, clusterTestType *examplev1.ClusterTestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.ClusterTestType, err error) { + if clusterTestType == nil { + return nil, fmt.Errorf("clusterTestType provided to Apply must not be nil") + } + data, err := json.Marshal(clusterTestType) + if err != nil { + return nil, err + } + name := clusterTestType.Name + if name == nil { + return nil, fmt.Errorf("clusterTestType.Name must be provided to Apply") + } + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clustertesttypesResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions(), "status"), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// GetScale takes name of the clusterTestType, and returns the corresponding scale object, and an error if there is any. +func (c *FakeClusterTestTypes) GetScale(ctx context.Context, clusterTestTypeName string, options metav1.GetOptions) (result *autoscalingv1.Scale, err error) { + emptyResult := &autoscalingv1.Scale{} + obj, err := c.Fake. + Invokes(testing.NewRootGetSubresourceActionWithOptions(clustertesttypesResource, "scale", clusterTestTypeName, options), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*autoscalingv1.Scale), err +} + +// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *FakeClusterTestTypes) UpdateScale(ctx context.Context, clusterTestTypeName string, scale *autoscalingv1.Scale, opts metav1.UpdateOptions) (result *autoscalingv1.Scale, err error) { + emptyResult := &autoscalingv1.Scale{} + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceActionWithOptions(clustertesttypesResource, "scale", scale, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*autoscalingv1.Scale), err +} diff --git a/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/fake/fake_example_client.go b/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/fake/fake_example_client.go new file mode 100644 index 000000000..1d97ad6ab --- /dev/null +++ b/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/fake/fake_example_client.go @@ -0,0 +1,44 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1" +) + +type FakeExampleGroupV1 struct { + *testing.Fake +} + +func (c *FakeExampleGroupV1) ClusterTestTypes() v1.ClusterTestTypeInterface { + return &FakeClusterTestTypes{c} +} + +func (c *FakeExampleGroupV1) TestTypes(namespace string) v1.TestTypeInterface { + return &FakeTestTypes{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeExampleGroupV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/fake/fake_testtype.go b/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/fake/fake_testtype.go new file mode 100644 index 000000000..39d0cc4a2 --- /dev/null +++ b/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/fake/fake_testtype.go @@ -0,0 +1,197 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + json "encoding/json" + fmt "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/HyphenGroup/apis/example/v1" + examplev1 "k8s.io/code-generator/examples/HyphenGroup/applyconfiguration/example/v1" +) + +// FakeTestTypes implements TestTypeInterface +type FakeTestTypes struct { + Fake *FakeExampleGroupV1 + ns string +} + +var testtypesResource = v1.SchemeGroupVersion.WithResource("testtypes") + +var testtypesKind = v1.SchemeGroupVersion.WithKind("TestType") + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewGetActionWithOptions(testtypesResource, c.ns, name, options), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *FakeTestTypes) List(ctx context.Context, opts metav1.ListOptions) (result *v1.TestTypeList, err error) { + emptyResult := &v1.TestTypeList{} + obj, err := c.Fake. + Invokes(testing.NewListActionWithOptions(testtypesResource, testtypesKind, c.ns, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1.TestTypeList{ListMeta: obj.(*v1.TestTypeList).ListMeta} + for _, item := range obj.(*v1.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchActionWithOptions(testtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Create(ctx context.Context, testType *v1.TestType, opts metav1.CreateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewCreateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Update(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTestTypes) UpdateStatus(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceActionWithOptions(testtypesResource, "status", c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *FakeTestTypes) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(testtypesResource, c.ns, name, opts), &v1.TestType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTestTypes) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + action := testing.NewDeleteCollectionActionWithOptions(testtypesResource, c.ns, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1.TestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched testType. +func (c *FakeTestTypes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied testType. +func (c *FakeTestTypes) Apply(ctx context.Context, testType *examplev1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.TestType, err error) { + if testType == nil { + return nil, fmt.Errorf("testType provided to Apply must not be nil") + } + data, err := json.Marshal(testType) + if err != nil { + return nil, err + } + name := testType.Name + if name == nil { + return nil, fmt.Errorf("testType.Name must be provided to Apply") + } + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeTestTypes) ApplyStatus(ctx context.Context, testType *examplev1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.TestType, err error) { + if testType == nil { + return nil, fmt.Errorf("testType provided to Apply must not be nil") + } + data, err := json.Marshal(testType) + if err != nil { + return nil, err + } + name := testType.Name + if name == nil { + return nil, fmt.Errorf("testType.Name must be provided to Apply") + } + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions(), "status"), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} diff --git a/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/generated_expansion.go b/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/generated_expansion.go new file mode 100644 index 000000000..3059734a9 --- /dev/null +++ b/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/generated_expansion.go @@ -0,0 +1,23 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type ClusterTestTypeExpansion interface{} + +type TestTypeExpansion interface{} diff --git a/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/testtype.go b/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/testtype.go new file mode 100644 index 000000000..ae38728a7 --- /dev/null +++ b/code-generator/examples/HyphenGroup/clientset/versioned/typed/example/v1/testtype.go @@ -0,0 +1,73 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + examplev1 "k8s.io/code-generator/examples/HyphenGroup/apis/example/v1" + applyconfigurationexamplev1 "k8s.io/code-generator/examples/HyphenGroup/applyconfiguration/example/v1" + scheme "k8s.io/code-generator/examples/HyphenGroup/clientset/versioned/scheme" +) + +// TestTypesGetter has a method to return a TestTypeInterface. +// A group's client should implement this interface. +type TestTypesGetter interface { + TestTypes(namespace string) TestTypeInterface +} + +// TestTypeInterface has methods to work with TestType resources. +type TestTypeInterface interface { + Create(ctx context.Context, testType *examplev1.TestType, opts metav1.CreateOptions) (*examplev1.TestType, error) + Update(ctx context.Context, testType *examplev1.TestType, opts metav1.UpdateOptions) (*examplev1.TestType, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, testType *examplev1.TestType, opts metav1.UpdateOptions) (*examplev1.TestType, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*examplev1.TestType, error) + List(ctx context.Context, opts metav1.ListOptions) (*examplev1.TestTypeList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *examplev1.TestType, err error) + Apply(ctx context.Context, testType *applyconfigurationexamplev1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *examplev1.TestType, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, testType *applyconfigurationexamplev1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *examplev1.TestType, err error) + TestTypeExpansion +} + +// testTypes implements TestTypeInterface +type testTypes struct { + *gentype.ClientWithListAndApply[*examplev1.TestType, *examplev1.TestTypeList, *applyconfigurationexamplev1.TestTypeApplyConfiguration] +} + +// newTestTypes returns a TestTypes +func newTestTypes(c *ExampleGroupV1Client, namespace string) *testTypes { + return &testTypes{ + gentype.NewClientWithListAndApply[*examplev1.TestType, *examplev1.TestTypeList, *applyconfigurationexamplev1.TestTypeApplyConfiguration]( + "testtypes", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *examplev1.TestType { return &examplev1.TestType{} }, + func() *examplev1.TestTypeList { return &examplev1.TestTypeList{} }), + } +} diff --git a/pkg/generated/informers/externalversions/samplecontroller/interface.go b/code-generator/examples/HyphenGroup/informers/externalversions/example/interface.go similarity index 69% rename from pkg/generated/informers/externalversions/samplecontroller/interface.go rename to code-generator/examples/HyphenGroup/informers/externalversions/example/interface.go index d06266ac5..a3a8658f3 100644 --- a/pkg/generated/informers/externalversions/samplecontroller/interface.go +++ b/code-generator/examples/HyphenGroup/informers/externalversions/example/interface.go @@ -16,17 +16,17 @@ limitations under the License. // Code generated by informer-gen. DO NOT EDIT. -package samplecontroller +package example import ( - internalinterfaces "k8s.io/sample-controller/pkg/generated/informers/externalversions/internalinterfaces" - v1alpha1 "k8s.io/sample-controller/pkg/generated/informers/externalversions/samplecontroller/v1alpha1" + v1 "k8s.io/code-generator/examples/HyphenGroup/informers/externalversions/example/v1" + internalinterfaces "k8s.io/code-generator/examples/HyphenGroup/informers/externalversions/internalinterfaces" ) // Interface provides access to each of this group's versions. type Interface interface { - // V1alpha1 provides access to shared informers for resources in V1alpha1. - V1alpha1() v1alpha1.Interface + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface } type group struct { @@ -40,7 +40,7 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} } -// V1alpha1 returns a new v1alpha1.Interface. -func (g *group) V1alpha1() v1alpha1.Interface { - return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) } diff --git a/code-generator/examples/HyphenGroup/informers/externalversions/example/v1/clustertesttype.go b/code-generator/examples/HyphenGroup/informers/externalversions/example/v1/clustertesttype.go new file mode 100644 index 000000000..d3621cba2 --- /dev/null +++ b/code-generator/examples/HyphenGroup/informers/externalversions/example/v1/clustertesttype.go @@ -0,0 +1,89 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + apisexamplev1 "k8s.io/code-generator/examples/HyphenGroup/apis/example/v1" + versioned "k8s.io/code-generator/examples/HyphenGroup/clientset/versioned" + internalinterfaces "k8s.io/code-generator/examples/HyphenGroup/informers/externalversions/internalinterfaces" + examplev1 "k8s.io/code-generator/examples/HyphenGroup/listers/example/v1" +) + +// ClusterTestTypeInformer provides access to a shared informer and lister for +// ClusterTestTypes. +type ClusterTestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() examplev1.ClusterTestTypeLister +} + +type clusterTestTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewClusterTestTypeInformer constructs a new informer for ClusterTestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewClusterTestTypeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredClusterTestTypeInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredClusterTestTypeInformer constructs a new informer for ClusterTestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredClusterTestTypeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleGroupV1().ClusterTestTypes().List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleGroupV1().ClusterTestTypes().Watch(context.TODO(), options) + }, + }, + &apisexamplev1.ClusterTestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *clusterTestTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredClusterTestTypeInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *clusterTestTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apisexamplev1.ClusterTestType{}, f.defaultInformer) +} + +func (f *clusterTestTypeInformer) Lister() examplev1.ClusterTestTypeLister { + return examplev1.NewClusterTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/code-generator/examples/HyphenGroup/informers/externalversions/example/v1/interface.go b/code-generator/examples/HyphenGroup/informers/externalversions/example/v1/interface.go new file mode 100644 index 000000000..27a2fdb83 --- /dev/null +++ b/code-generator/examples/HyphenGroup/informers/externalversions/example/v1/interface.go @@ -0,0 +1,52 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "k8s.io/code-generator/examples/HyphenGroup/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // ClusterTestTypes returns a ClusterTestTypeInformer. + ClusterTestTypes() ClusterTestTypeInformer + // TestTypes returns a TestTypeInformer. + TestTypes() TestTypeInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// ClusterTestTypes returns a ClusterTestTypeInformer. +func (v *version) ClusterTestTypes() ClusterTestTypeInformer { + return &clusterTestTypeInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + +// TestTypes returns a TestTypeInformer. +func (v *version) TestTypes() TestTypeInformer { + return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/code-generator/examples/HyphenGroup/informers/externalversions/example/v1/testtype.go b/code-generator/examples/HyphenGroup/informers/externalversions/example/v1/testtype.go new file mode 100644 index 000000000..8a15993b8 --- /dev/null +++ b/code-generator/examples/HyphenGroup/informers/externalversions/example/v1/testtype.go @@ -0,0 +1,90 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + apisexamplev1 "k8s.io/code-generator/examples/HyphenGroup/apis/example/v1" + versioned "k8s.io/code-generator/examples/HyphenGroup/clientset/versioned" + internalinterfaces "k8s.io/code-generator/examples/HyphenGroup/informers/externalversions/internalinterfaces" + examplev1 "k8s.io/code-generator/examples/HyphenGroup/listers/example/v1" +) + +// TestTypeInformer provides access to a shared informer and lister for +// TestTypes. +type TestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() examplev1.TestTypeLister +} + +type testTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleGroupV1().TestTypes(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleGroupV1().TestTypes(namespace).Watch(context.TODO(), options) + }, + }, + &apisexamplev1.TestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *testTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apisexamplev1.TestType{}, f.defaultInformer) +} + +func (f *testTypeInformer) Lister() examplev1.TestTypeLister { + return examplev1.NewTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/pkg/generated/informers/externalversions/factory.go b/code-generator/examples/HyphenGroup/informers/externalversions/factory.go similarity index 94% rename from pkg/generated/informers/externalversions/factory.go rename to code-generator/examples/HyphenGroup/informers/externalversions/factory.go index 46b47b657..a3cd3f40e 100644 --- a/pkg/generated/informers/externalversions/factory.go +++ b/code-generator/examples/HyphenGroup/informers/externalversions/factory.go @@ -27,9 +27,9 @@ import ( runtime "k8s.io/apimachinery/pkg/runtime" schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" - versioned "k8s.io/sample-controller/pkg/generated/clientset/versioned" - internalinterfaces "k8s.io/sample-controller/pkg/generated/informers/externalversions/internalinterfaces" - samplecontroller "k8s.io/sample-controller/pkg/generated/informers/externalversions/samplecontroller" + versioned "k8s.io/code-generator/examples/HyphenGroup/clientset/versioned" + example "k8s.io/code-generator/examples/HyphenGroup/informers/externalversions/example" + internalinterfaces "k8s.io/code-generator/examples/HyphenGroup/informers/externalversions/internalinterfaces" ) // SharedInformerOption defines the functional option type for SharedInformerFactory. @@ -254,9 +254,9 @@ type SharedInformerFactory interface { // client. InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer - Samplecontroller() samplecontroller.Interface + ExampleGroup() example.Interface } -func (f *sharedInformerFactory) Samplecontroller() samplecontroller.Interface { - return samplecontroller.New(f, f.namespace, f.tweakListOptions) +func (f *sharedInformerFactory) ExampleGroup() example.Interface { + return example.New(f, f.namespace, f.tweakListOptions) } diff --git a/code-generator/examples/HyphenGroup/informers/externalversions/generic.go b/code-generator/examples/HyphenGroup/informers/externalversions/generic.go new file mode 100644 index 000000000..65cfad069 --- /dev/null +++ b/code-generator/examples/HyphenGroup/informers/externalversions/generic.go @@ -0,0 +1,64 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + fmt "fmt" + + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + v1 "k8s.io/code-generator/examples/HyphenGroup/apis/example/v1" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=example-group.hyphens.code-generator.k8s.io, Version=v1 + case v1.SchemeGroupVersion.WithResource("clustertesttypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.ExampleGroup().V1().ClusterTestTypes().Informer()}, nil + case v1.SchemeGroupVersion.WithResource("testtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.ExampleGroup().V1().TestTypes().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/code-generator/examples/HyphenGroup/informers/externalversions/internalinterfaces/factory_interfaces.go b/code-generator/examples/HyphenGroup/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 000000000..6169d2617 --- /dev/null +++ b/code-generator/examples/HyphenGroup/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" + versioned "k8s.io/code-generator/examples/HyphenGroup/clientset/versioned" +) + +// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +// TweakListOptionsFunc is a function that transforms a v1.ListOptions. +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/code-generator/examples/HyphenGroup/listers/example/v1/clustertesttype.go b/code-generator/examples/HyphenGroup/listers/example/v1/clustertesttype.go new file mode 100644 index 000000000..d4aa80fb9 --- /dev/null +++ b/code-generator/examples/HyphenGroup/listers/example/v1/clustertesttype.go @@ -0,0 +1,48 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" + examplev1 "k8s.io/code-generator/examples/HyphenGroup/apis/example/v1" +) + +// ClusterTestTypeLister helps list ClusterTestTypes. +// All objects returned here must be treated as read-only. +type ClusterTestTypeLister interface { + // List lists all ClusterTestTypes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*examplev1.ClusterTestType, err error) + // Get retrieves the ClusterTestType from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*examplev1.ClusterTestType, error) + ClusterTestTypeListerExpansion +} + +// clusterTestTypeLister implements the ClusterTestTypeLister interface. +type clusterTestTypeLister struct { + listers.ResourceIndexer[*examplev1.ClusterTestType] +} + +// NewClusterTestTypeLister returns a new ClusterTestTypeLister. +func NewClusterTestTypeLister(indexer cache.Indexer) ClusterTestTypeLister { + return &clusterTestTypeLister{listers.New[*examplev1.ClusterTestType](indexer, examplev1.Resource("clustertesttype"))} +} diff --git a/code-generator/examples/HyphenGroup/listers/example/v1/expansion_generated.go b/code-generator/examples/HyphenGroup/listers/example/v1/expansion_generated.go new file mode 100644 index 000000000..2681a29f4 --- /dev/null +++ b/code-generator/examples/HyphenGroup/listers/example/v1/expansion_generated.go @@ -0,0 +1,31 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// ClusterTestTypeListerExpansion allows custom methods to be added to +// ClusterTestTypeLister. +type ClusterTestTypeListerExpansion interface{} + +// TestTypeListerExpansion allows custom methods to be added to +// TestTypeLister. +type TestTypeListerExpansion interface{} + +// TestTypeNamespaceListerExpansion allows custom methods to be added to +// TestTypeNamespaceLister. +type TestTypeNamespaceListerExpansion interface{} diff --git a/code-generator/examples/HyphenGroup/listers/example/v1/testtype.go b/code-generator/examples/HyphenGroup/listers/example/v1/testtype.go new file mode 100644 index 000000000..47364c0cd --- /dev/null +++ b/code-generator/examples/HyphenGroup/listers/example/v1/testtype.go @@ -0,0 +1,70 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" + examplev1 "k8s.io/code-generator/examples/HyphenGroup/apis/example/v1" +) + +// TestTypeLister helps list TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeLister interface { + // List lists all TestTypes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*examplev1.TestType, err error) + // TestTypes returns an object that can list and get TestTypes. + TestTypes(namespace string) TestTypeNamespaceLister + TestTypeListerExpansion +} + +// testTypeLister implements the TestTypeLister interface. +type testTypeLister struct { + listers.ResourceIndexer[*examplev1.TestType] +} + +// NewTestTypeLister returns a new TestTypeLister. +func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { + return &testTypeLister{listers.New[*examplev1.TestType](indexer, examplev1.Resource("testtype"))} +} + +// TestTypes returns an object that can list and get TestTypes. +func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { + return testTypeNamespaceLister{listers.NewNamespaced[*examplev1.TestType](s.ResourceIndexer, namespace)} +} + +// TestTypeNamespaceLister helps list and get TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeNamespaceLister interface { + // List lists all TestTypes in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*examplev1.TestType, err error) + // Get retrieves the TestType from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*examplev1.TestType, error) + TestTypeNamespaceListerExpansion +} + +// testTypeNamespaceLister implements the TestTypeNamespaceLister +// interface. +type testTypeNamespaceLister struct { + listers.ResourceIndexer[*examplev1.TestType] +} diff --git a/code-generator/examples/MixedCase/apis/example/v1/doc.go b/code-generator/examples/MixedCase/apis/example/v1/doc.go new file mode 100644 index 000000000..5012b4f63 --- /dev/null +++ b/code-generator/examples/MixedCase/apis/example/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2016 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:defaulter-gen=TypeMeta +// +groupName=example.crd.code-generator.k8s.io +package v1 // import "k8s.io/code-generator/examples/MixedCase/apis/example/v1" diff --git a/code-generator/examples/MixedCase/apis/example/v1/register.go b/code-generator/examples/MixedCase/apis/example/v1/register.go new file mode 100644 index 000000000..58371e0e9 --- /dev/null +++ b/code-generator/examples/MixedCase/apis/example/v1/register.go @@ -0,0 +1,59 @@ +/* +Copyright 2015 The Kubernetes 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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.crd.code-generator.k8s.io", Version: "v1"} + +var ( + // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion, + &metav1.Status{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/code-generator/examples/MixedCase/apis/example/v1/types.go b/code-generator/examples/MixedCase/apis/example/v1/types.go new file mode 100644 index 000000000..f74e27cee --- /dev/null +++ b/code-generator/examples/MixedCase/apis/example/v1/types.go @@ -0,0 +1,76 @@ +/* +Copyright 2015 The Kubernetes 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 v1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status TestTypeStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []TestType `json:"items"` +} + +type TestTypeStatus struct { + Blah string `json:"blah"` +} + +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type ClusterTestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + Items []ClusterTestType `json:"items"` +} + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient:method=GetScale,verb=get,subresource=scale,result=k8s.io/api/autoscaling/v1.Scale +// +genclient:method=UpdateScale,verb=update,subresource=scale,input=k8s.io/api/autoscaling/v1.Scale,result=k8s.io/api/autoscaling/v1.Scale +// +genclient:method=CreateScale,verb=create,subresource=scale,input=k8s.io/api/autoscaling/v1.Scale,result=k8s.io/api/autoscaling/v1.Scale + +type ClusterTestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status ClusterTestTypeStatus `json:"status,omitempty"` +} + +type ClusterTestTypeStatus struct { + Blah string `json:"blah"` +} diff --git a/code-generator/examples/MixedCase/apis/example/v1/zz_generated.deepcopy.go b/code-generator/examples/MixedCase/apis/example/v1/zz_generated.deepcopy.go new file mode 100644 index 000000000..5eee47016 --- /dev/null +++ b/code-generator/examples/MixedCase/apis/example/v1/zz_generated.deepcopy.go @@ -0,0 +1,178 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestType) DeepCopyInto(out *ClusterTestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestType. +func (in *ClusterTestType) DeepCopy() *ClusterTestType { + if in == nil { + return nil + } + out := new(ClusterTestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterTestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestTypeList) DeepCopyInto(out *ClusterTestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ClusterTestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestTypeList. +func (in *ClusterTestTypeList) DeepCopy() *ClusterTestTypeList { + if in == nil { + return nil + } + out := new(ClusterTestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterTestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestTypeStatus) DeepCopyInto(out *ClusterTestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestTypeStatus. +func (in *ClusterTestTypeStatus) DeepCopy() *ClusterTestTypeStatus { + if in == nil { + return nil + } + out := new(ClusterTestTypeStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/examples/MixedCase/apis/example/v1/zz_generated.defaults.go b/code-generator/examples/MixedCase/apis/example/v1/zz_generated.defaults.go new file mode 100644 index 000000000..dac177e93 --- /dev/null +++ b/code-generator/examples/MixedCase/apis/example/v1/zz_generated.defaults.go @@ -0,0 +1,33 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/code-generator/examples/MixedCase/applyconfiguration/example/v1/clustertesttype.go b/code-generator/examples/MixedCase/applyconfiguration/example/v1/clustertesttype.go new file mode 100644 index 000000000..49ceb182a --- /dev/null +++ b/code-generator/examples/MixedCase/applyconfiguration/example/v1/clustertesttype.go @@ -0,0 +1,215 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +import ( + apismetav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + metav1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// ClusterTestTypeApplyConfiguration represents a declarative configuration of the ClusterTestType type for use +// with apply. +type ClusterTestTypeApplyConfiguration struct { + metav1.TypeMetaApplyConfiguration `json:",inline"` + *metav1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Status *ClusterTestTypeStatusApplyConfiguration `json:"status,omitempty"` +} + +// ClusterTestType constructs a declarative configuration of the ClusterTestType type for use with +// apply. +func ClusterTestType(name string) *ClusterTestTypeApplyConfiguration { + b := &ClusterTestTypeApplyConfiguration{} + b.WithName(name) + b.WithKind("ClusterTestType") + b.WithAPIVersion("example.crd.code-generator.k8s.io/v1") + return b +} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithKind(value string) *ClusterTestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithAPIVersion(value string) *ClusterTestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithName(value string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithGenerateName(value string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithNamespace(value string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithUID(value types.UID) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithResourceVersion(value string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithGeneration(value int64) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithCreationTimestamp(value apismetav1.Time) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithDeletionTimestamp(value apismetav1.Time) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *ClusterTestTypeApplyConfiguration) WithLabels(entries map[string]string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *ClusterTestTypeApplyConfiguration) WithAnnotations(entries map[string]string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *ClusterTestTypeApplyConfiguration) WithOwnerReferences(values ...*metav1.OwnerReferenceApplyConfiguration) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *ClusterTestTypeApplyConfiguration) WithFinalizers(values ...string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *ClusterTestTypeApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &metav1.ObjectMetaApplyConfiguration{} + } +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithStatus(value *ClusterTestTypeStatusApplyConfiguration) *ClusterTestTypeApplyConfiguration { + b.Status = value + return b +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *ClusterTestTypeApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} diff --git a/code-generator/examples/MixedCase/applyconfiguration/example/v1/clustertesttypestatus.go b/code-generator/examples/MixedCase/applyconfiguration/example/v1/clustertesttypestatus.go new file mode 100644 index 000000000..c2ccfa581 --- /dev/null +++ b/code-generator/examples/MixedCase/applyconfiguration/example/v1/clustertesttypestatus.go @@ -0,0 +1,39 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// ClusterTestTypeStatusApplyConfiguration represents a declarative configuration of the ClusterTestTypeStatus type for use +// with apply. +type ClusterTestTypeStatusApplyConfiguration struct { + Blah *string `json:"blah,omitempty"` +} + +// ClusterTestTypeStatusApplyConfiguration constructs a declarative configuration of the ClusterTestTypeStatus type for use with +// apply. +func ClusterTestTypeStatus() *ClusterTestTypeStatusApplyConfiguration { + return &ClusterTestTypeStatusApplyConfiguration{} +} + +// WithBlah sets the Blah field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Blah field is set to the value of the last call. +func (b *ClusterTestTypeStatusApplyConfiguration) WithBlah(value string) *ClusterTestTypeStatusApplyConfiguration { + b.Blah = &value + return b +} diff --git a/code-generator/examples/MixedCase/applyconfiguration/example/v1/testtype.go b/code-generator/examples/MixedCase/applyconfiguration/example/v1/testtype.go new file mode 100644 index 000000000..49fdd2a66 --- /dev/null +++ b/code-generator/examples/MixedCase/applyconfiguration/example/v1/testtype.go @@ -0,0 +1,216 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +import ( + apismetav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + metav1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// TestTypeApplyConfiguration represents a declarative configuration of the TestType type for use +// with apply. +type TestTypeApplyConfiguration struct { + metav1.TypeMetaApplyConfiguration `json:",inline"` + *metav1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Status *TestTypeStatusApplyConfiguration `json:"status,omitempty"` +} + +// TestType constructs a declarative configuration of the TestType type for use with +// apply. +func TestType(name, namespace string) *TestTypeApplyConfiguration { + b := &TestTypeApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("TestType") + b.WithAPIVersion("example.crd.code-generator.k8s.io/v1") + return b +} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithKind(value string) *TestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithAPIVersion(value string) *TestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithName(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithGenerateName(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithNamespace(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithUID(value types.UID) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithResourceVersion(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithGeneration(value int64) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithCreationTimestamp(value apismetav1.Time) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithDeletionTimestamp(value apismetav1.Time) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *TestTypeApplyConfiguration) WithLabels(entries map[string]string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *TestTypeApplyConfiguration) WithAnnotations(entries map[string]string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *TestTypeApplyConfiguration) WithOwnerReferences(values ...*metav1.OwnerReferenceApplyConfiguration) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *TestTypeApplyConfiguration) WithFinalizers(values ...string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *TestTypeApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &metav1.ObjectMetaApplyConfiguration{} + } +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithStatus(value *TestTypeStatusApplyConfiguration) *TestTypeApplyConfiguration { + b.Status = value + return b +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *TestTypeApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} diff --git a/code-generator/examples/MixedCase/applyconfiguration/example/v1/testtypestatus.go b/code-generator/examples/MixedCase/applyconfiguration/example/v1/testtypestatus.go new file mode 100644 index 000000000..246b2ee18 --- /dev/null +++ b/code-generator/examples/MixedCase/applyconfiguration/example/v1/testtypestatus.go @@ -0,0 +1,39 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// TestTypeStatusApplyConfiguration represents a declarative configuration of the TestTypeStatus type for use +// with apply. +type TestTypeStatusApplyConfiguration struct { + Blah *string `json:"blah,omitempty"` +} + +// TestTypeStatusApplyConfiguration constructs a declarative configuration of the TestTypeStatus type for use with +// apply. +func TestTypeStatus() *TestTypeStatusApplyConfiguration { + return &TestTypeStatusApplyConfiguration{} +} + +// WithBlah sets the Blah field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Blah field is set to the value of the last call. +func (b *TestTypeStatusApplyConfiguration) WithBlah(value string) *TestTypeStatusApplyConfiguration { + b.Blah = &value + return b +} diff --git a/code-generator/examples/MixedCase/applyconfiguration/internal/internal.go b/code-generator/examples/MixedCase/applyconfiguration/internal/internal.go new file mode 100644 index 000000000..1064e227e --- /dev/null +++ b/code-generator/examples/MixedCase/applyconfiguration/internal/internal.go @@ -0,0 +1,62 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package internal + +import ( + fmt "fmt" + sync "sync" + + typed "sigs.k8s.io/structured-merge-diff/v4/typed" +) + +func Parser() *typed.Parser { + parserOnce.Do(func() { + var err error + parser, err = typed.NewParser(schemaYAML) + if err != nil { + panic(fmt.Sprintf("Failed to parse schema: %v", err)) + } + }) + return parser +} + +var parserOnce sync.Once +var parser *typed.Parser +var schemaYAML = typed.YAMLObject(`types: +- name: __untyped_atomic_ + scalar: untyped + list: + elementType: + namedType: __untyped_atomic_ + elementRelationship: atomic + map: + elementType: + namedType: __untyped_atomic_ + elementRelationship: atomic +- name: __untyped_deduced_ + scalar: untyped + list: + elementType: + namedType: __untyped_atomic_ + elementRelationship: atomic + map: + elementType: + namedType: __untyped_deduced_ + elementRelationship: separable +`) diff --git a/code-generator/examples/MixedCase/applyconfiguration/utils.go b/code-generator/examples/MixedCase/applyconfiguration/utils.go new file mode 100644 index 000000000..c28368a44 --- /dev/null +++ b/code-generator/examples/MixedCase/applyconfiguration/utils.go @@ -0,0 +1,50 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package applyconfiguration + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/MixedCase/apis/example/v1" + examplev1 "k8s.io/code-generator/examples/MixedCase/applyconfiguration/example/v1" + internal "k8s.io/code-generator/examples/MixedCase/applyconfiguration/internal" +) + +// ForKind returns an apply configuration type for the given GroupVersionKind, or nil if no +// apply configuration type exists for the given GroupVersionKind. +func ForKind(kind schema.GroupVersionKind) interface{} { + switch kind { + // Group=example.crd.code-generator.k8s.io, Version=v1 + case v1.SchemeGroupVersion.WithKind("ClusterTestType"): + return &examplev1.ClusterTestTypeApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("ClusterTestTypeStatus"): + return &examplev1.ClusterTestTypeStatusApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("TestType"): + return &examplev1.TestTypeApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("TestTypeStatus"): + return &examplev1.TestTypeStatusApplyConfiguration{} + + } + return nil +} + +func NewTypeConverter(scheme *runtime.Scheme) *testing.TypeConverter { + return &testing.TypeConverter{Scheme: scheme, TypeResolver: internal.Parser()} +} diff --git a/code-generator/examples/MixedCase/clientset/versioned/clientset.go b/code-generator/examples/MixedCase/clientset/versioned/clientset.go new file mode 100644 index 000000000..f088bb637 --- /dev/null +++ b/code-generator/examples/MixedCase/clientset/versioned/clientset.go @@ -0,0 +1,120 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package versioned + +import ( + fmt "fmt" + http "net/http" + + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" + examplev1 "k8s.io/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + ExampleV1() examplev1.ExampleV1Interface +} + +// Clientset contains the clients for groups. +type Clientset struct { + *discovery.DiscoveryClient + exampleV1 *examplev1.ExampleV1Client +} + +// ExampleV1 retrieves the ExampleV1Client +func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { + return c.exampleV1 +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfig will generate a rate-limiter in configShallowCopy. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + + if configShallowCopy.UserAgent == "" { + configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent() + } + + // share the transport between all clients + httpClient, err := rest.HTTPClientFor(&configShallowCopy) + if err != nil { + return nil, err + } + + return NewForConfigAndClient(&configShallowCopy, httpClient) +} + +// NewForConfigAndClient creates a new Clientset for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfigAndClient will generate a rate-limiter in configShallowCopy. +func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + if configShallowCopy.Burst <= 0 { + return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") + } + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + + var cs Clientset + var err error + cs.exampleV1, err = examplev1.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + cs, err := NewForConfig(c) + if err != nil { + panic(err) + } + return cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.exampleV1 = examplev1.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/code-generator/examples/MixedCase/clientset/versioned/fake/clientset_generated.go b/code-generator/examples/MixedCase/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 000000000..8a6950b13 --- /dev/null +++ b/code-generator/examples/MixedCase/clientset/versioned/fake/clientset_generated.go @@ -0,0 +1,122 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" + applyconfiguration "k8s.io/code-generator/examples/MixedCase/applyconfiguration" + clientset "k8s.io/code-generator/examples/MixedCase/clientset/versioned" + examplev1 "k8s.io/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1" + fakeexamplev1 "k8s.io/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/fake" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any field management, validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +// +// DEPRECATED: NewClientset replaces this with support for field management, which significantly improves +// server side apply testing. NewClientset is only available when apply configurations are generated (e.g. +// via --with-applyconfig). +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery + tracker testing.ObjectTracker +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +func (c *Clientset) Tracker() testing.ObjectTracker { + return c.tracker +} + +// NewClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewClientset(objects ...runtime.Object) *Clientset { + o := testing.NewFieldManagedObjectTracker( + scheme, + codecs.UniversalDecoder(), + applyconfiguration.NewTypeConverter(scheme), + ) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +var ( + _ clientset.Interface = &Clientset{} + _ testing.FakeClient = &Clientset{} +) + +// ExampleV1 retrieves the ExampleV1Client +func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { + return &fakeexamplev1.FakeExampleV1{Fake: &c.Fake} +} diff --git a/code-generator/examples/MixedCase/clientset/versioned/fake/doc.go b/code-generator/examples/MixedCase/clientset/versioned/fake/doc.go new file mode 100644 index 000000000..9b99e7167 --- /dev/null +++ b/code-generator/examples/MixedCase/clientset/versioned/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/code-generator/examples/MixedCase/clientset/versioned/fake/register.go b/code-generator/examples/MixedCase/clientset/versioned/fake/register.go new file mode 100644 index 000000000..4711b6ae1 --- /dev/null +++ b/code-generator/examples/MixedCase/clientset/versioned/fake/register.go @@ -0,0 +1,56 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + examplev1 "k8s.io/code-generator/examples/MixedCase/apis/example/v1" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) + +var localSchemeBuilder = runtime.SchemeBuilder{ + examplev1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) +} diff --git a/code-generator/examples/MixedCase/clientset/versioned/scheme/doc.go b/code-generator/examples/MixedCase/clientset/versioned/scheme/doc.go new file mode 100644 index 000000000..7dc375616 --- /dev/null +++ b/code-generator/examples/MixedCase/clientset/versioned/scheme/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/code-generator/examples/MixedCase/clientset/versioned/scheme/register.go b/code-generator/examples/MixedCase/clientset/versioned/scheme/register.go new file mode 100644 index 000000000..472da566e --- /dev/null +++ b/code-generator/examples/MixedCase/clientset/versioned/scheme/register.go @@ -0,0 +1,56 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + examplev1 "k8s.io/code-generator/examples/MixedCase/apis/example/v1" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + examplev1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(Scheme)) +} diff --git a/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/clustertesttype.go b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/clustertesttype.go new file mode 100644 index 000000000..81367683e --- /dev/null +++ b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/clustertesttype.go @@ -0,0 +1,119 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + + autoscalingv1 "k8s.io/api/autoscaling/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + examplev1 "k8s.io/code-generator/examples/MixedCase/apis/example/v1" + applyconfigurationexamplev1 "k8s.io/code-generator/examples/MixedCase/applyconfiguration/example/v1" + scheme "k8s.io/code-generator/examples/MixedCase/clientset/versioned/scheme" +) + +// ClusterTestTypesGetter has a method to return a ClusterTestTypeInterface. +// A group's client should implement this interface. +type ClusterTestTypesGetter interface { + ClusterTestTypes() ClusterTestTypeInterface +} + +// ClusterTestTypeInterface has methods to work with ClusterTestType resources. +type ClusterTestTypeInterface interface { + Create(ctx context.Context, clusterTestType *examplev1.ClusterTestType, opts metav1.CreateOptions) (*examplev1.ClusterTestType, error) + Update(ctx context.Context, clusterTestType *examplev1.ClusterTestType, opts metav1.UpdateOptions) (*examplev1.ClusterTestType, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, clusterTestType *examplev1.ClusterTestType, opts metav1.UpdateOptions) (*examplev1.ClusterTestType, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*examplev1.ClusterTestType, error) + List(ctx context.Context, opts metav1.ListOptions) (*examplev1.ClusterTestTypeList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *examplev1.ClusterTestType, err error) + Apply(ctx context.Context, clusterTestType *applyconfigurationexamplev1.ClusterTestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *examplev1.ClusterTestType, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, clusterTestType *applyconfigurationexamplev1.ClusterTestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *examplev1.ClusterTestType, err error) + GetScale(ctx context.Context, clusterTestTypeName string, options metav1.GetOptions) (*autoscalingv1.Scale, error) + UpdateScale(ctx context.Context, clusterTestTypeName string, scale *autoscalingv1.Scale, opts metav1.UpdateOptions) (*autoscalingv1.Scale, error) + CreateScale(ctx context.Context, clusterTestTypeName string, scale *autoscalingv1.Scale, opts metav1.CreateOptions) (*autoscalingv1.Scale, error) + + ClusterTestTypeExpansion +} + +// clusterTestTypes implements ClusterTestTypeInterface +type clusterTestTypes struct { + *gentype.ClientWithListAndApply[*examplev1.ClusterTestType, *examplev1.ClusterTestTypeList, *applyconfigurationexamplev1.ClusterTestTypeApplyConfiguration] +} + +// newClusterTestTypes returns a ClusterTestTypes +func newClusterTestTypes(c *ExampleV1Client) *clusterTestTypes { + return &clusterTestTypes{ + gentype.NewClientWithListAndApply[*examplev1.ClusterTestType, *examplev1.ClusterTestTypeList, *applyconfigurationexamplev1.ClusterTestTypeApplyConfiguration]( + "clustertesttypes", + c.RESTClient(), + scheme.ParameterCodec, + "", + func() *examplev1.ClusterTestType { return &examplev1.ClusterTestType{} }, + func() *examplev1.ClusterTestTypeList { return &examplev1.ClusterTestTypeList{} }), + } +} + +// GetScale takes name of the clusterTestType, and returns the corresponding autoscalingv1.Scale object, and an error if there is any. +func (c *clusterTestTypes) GetScale(ctx context.Context, clusterTestTypeName string, options metav1.GetOptions) (result *autoscalingv1.Scale, err error) { + result = &autoscalingv1.Scale{} + err = c.GetClient().Get(). + Resource("clustertesttypes"). + Name(clusterTestTypeName). + SubResource("scale"). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *clusterTestTypes) UpdateScale(ctx context.Context, clusterTestTypeName string, scale *autoscalingv1.Scale, opts metav1.UpdateOptions) (result *autoscalingv1.Scale, err error) { + result = &autoscalingv1.Scale{} + err = c.GetClient().Put(). + Resource("clustertesttypes"). + Name(clusterTestTypeName). + SubResource("scale"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(scale). + Do(ctx). + Into(result) + return +} + +// CreateScale takes the representation of a scale and creates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *clusterTestTypes) CreateScale(ctx context.Context, clusterTestTypeName string, scale *autoscalingv1.Scale, opts metav1.CreateOptions) (result *autoscalingv1.Scale, err error) { + result = &autoscalingv1.Scale{} + err = c.GetClient().Post(). + Resource("clustertesttypes"). + Name(clusterTestTypeName). + SubResource("scale"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(scale). + Do(ctx). + Into(result) + return +} diff --git a/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/doc.go b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/doc.go new file mode 100644 index 000000000..3af5d054f --- /dev/null +++ b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/example_client.go b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/example_client.go new file mode 100644 index 000000000..91f819822 --- /dev/null +++ b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/example_client.go @@ -0,0 +1,112 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + http "net/http" + + rest "k8s.io/client-go/rest" + examplev1 "k8s.io/code-generator/examples/MixedCase/apis/example/v1" + scheme "k8s.io/code-generator/examples/MixedCase/clientset/versioned/scheme" +) + +type ExampleV1Interface interface { + RESTClient() rest.Interface + ClusterTestTypesGetter + TestTypesGetter +} + +// ExampleV1Client is used to interact with features provided by the example.crd.code-generator.k8s.io group. +type ExampleV1Client struct { + restClient rest.Interface +} + +func (c *ExampleV1Client) ClusterTestTypes() ClusterTestTypeInterface { + return newClusterTestTypes(c) +} + +func (c *ExampleV1Client) TestTypes(namespace string) TestTypeInterface { + return newTestTypes(c, namespace) +} + +// NewForConfig creates a new ExampleV1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*ExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new ExampleV1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*ExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &ExampleV1Client{client}, nil +} + +// NewForConfigOrDie creates a new ExampleV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ExampleV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ExampleV1Client for the given RESTClient. +func New(c rest.Interface) *ExampleV1Client { + return &ExampleV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := examplev1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *ExampleV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/fake/doc.go b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go new file mode 100644 index 000000000..c64103b5f --- /dev/null +++ b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go @@ -0,0 +1,220 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + json "encoding/json" + fmt "fmt" + + autoscalingv1 "k8s.io/api/autoscaling/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/MixedCase/apis/example/v1" + examplev1 "k8s.io/code-generator/examples/MixedCase/applyconfiguration/example/v1" +) + +// FakeClusterTestTypes implements ClusterTestTypeInterface +type FakeClusterTestTypes struct { + Fake *FakeExampleV1 +} + +var clustertesttypesResource = v1.SchemeGroupVersion.WithResource("clustertesttypes") + +var clustertesttypesKind = v1.SchemeGroupVersion.WithKind("ClusterTestType") + +// Get takes name of the clusterTestType, and returns the corresponding clusterTestType object, and an error if there is any. +func (c *FakeClusterTestTypes) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootGetActionWithOptions(clustertesttypesResource, name, options), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// List takes label and field selectors, and returns the list of ClusterTestTypes that match those selectors. +func (c *FakeClusterTestTypes) List(ctx context.Context, opts metav1.ListOptions) (result *v1.ClusterTestTypeList, err error) { + emptyResult := &v1.ClusterTestTypeList{} + obj, err := c.Fake. + Invokes(testing.NewRootListActionWithOptions(clustertesttypesResource, clustertesttypesKind, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1.ClusterTestTypeList{ListMeta: obj.(*v1.ClusterTestTypeList).ListMeta} + for _, item := range obj.(*v1.ClusterTestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested clusterTestTypes. +func (c *FakeClusterTestTypes) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchActionWithOptions(clustertesttypesResource, opts)) +} + +// Create takes the representation of a clusterTestType and creates it. Returns the server's representation of the clusterTestType, and an error, if there is any. +func (c *FakeClusterTestTypes) Create(ctx context.Context, clusterTestType *v1.ClusterTestType, opts metav1.CreateOptions) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootCreateActionWithOptions(clustertesttypesResource, clusterTestType, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// Update takes the representation of a clusterTestType and updates it. Returns the server's representation of the clusterTestType, and an error, if there is any. +func (c *FakeClusterTestTypes) Update(ctx context.Context, clusterTestType *v1.ClusterTestType, opts metav1.UpdateOptions) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootUpdateActionWithOptions(clustertesttypesResource, clusterTestType, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeClusterTestTypes) UpdateStatus(ctx context.Context, clusterTestType *v1.ClusterTestType, opts metav1.UpdateOptions) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceActionWithOptions(clustertesttypesResource, "status", clusterTestType, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// Delete takes name of the clusterTestType and deletes it. Returns an error if one occurs. +func (c *FakeClusterTestTypes) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(clustertesttypesResource, name, opts), &v1.ClusterTestType{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeClusterTestTypes) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + action := testing.NewRootDeleteCollectionActionWithOptions(clustertesttypesResource, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1.ClusterTestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched clusterTestType. +func (c *FakeClusterTestTypes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clustertesttypesResource, name, pt, data, opts, subresources...), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied clusterTestType. +func (c *FakeClusterTestTypes) Apply(ctx context.Context, clusterTestType *examplev1.ClusterTestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.ClusterTestType, err error) { + if clusterTestType == nil { + return nil, fmt.Errorf("clusterTestType provided to Apply must not be nil") + } + data, err := json.Marshal(clusterTestType) + if err != nil { + return nil, err + } + name := clusterTestType.Name + if name == nil { + return nil, fmt.Errorf("clusterTestType.Name must be provided to Apply") + } + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clustertesttypesResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeClusterTestTypes) ApplyStatus(ctx context.Context, clusterTestType *examplev1.ClusterTestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.ClusterTestType, err error) { + if clusterTestType == nil { + return nil, fmt.Errorf("clusterTestType provided to Apply must not be nil") + } + data, err := json.Marshal(clusterTestType) + if err != nil { + return nil, err + } + name := clusterTestType.Name + if name == nil { + return nil, fmt.Errorf("clusterTestType.Name must be provided to Apply") + } + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clustertesttypesResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions(), "status"), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// GetScale takes name of the clusterTestType, and returns the corresponding scale object, and an error if there is any. +func (c *FakeClusterTestTypes) GetScale(ctx context.Context, clusterTestTypeName string, options metav1.GetOptions) (result *autoscalingv1.Scale, err error) { + emptyResult := &autoscalingv1.Scale{} + obj, err := c.Fake. + Invokes(testing.NewRootGetSubresourceActionWithOptions(clustertesttypesResource, "scale", clusterTestTypeName, options), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*autoscalingv1.Scale), err +} + +// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *FakeClusterTestTypes) UpdateScale(ctx context.Context, clusterTestTypeName string, scale *autoscalingv1.Scale, opts metav1.UpdateOptions) (result *autoscalingv1.Scale, err error) { + emptyResult := &autoscalingv1.Scale{} + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceActionWithOptions(clustertesttypesResource, "scale", scale, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*autoscalingv1.Scale), err +} + +// CreateScale takes the representation of a scale and creates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *FakeClusterTestTypes) CreateScale(ctx context.Context, clusterTestTypeName string, scale *autoscalingv1.Scale, opts metav1.CreateOptions) (result *autoscalingv1.Scale, err error) { + emptyResult := &autoscalingv1.Scale{} + obj, err := c.Fake. + Invokes(testing.NewRootCreateSubresourceActionWithOptions(clustertesttypesResource, clusterTestTypeName, "scale", scale, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*autoscalingv1.Scale), err +} diff --git a/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_example_client.go b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_example_client.go new file mode 100644 index 000000000..b545f5b92 --- /dev/null +++ b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_example_client.go @@ -0,0 +1,44 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1" +) + +type FakeExampleV1 struct { + *testing.Fake +} + +func (c *FakeExampleV1) ClusterTestTypes() v1.ClusterTestTypeInterface { + return &FakeClusterTestTypes{c} +} + +func (c *FakeExampleV1) TestTypes(namespace string) v1.TestTypeInterface { + return &FakeTestTypes{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeExampleV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_testtype.go b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_testtype.go new file mode 100644 index 000000000..8aafcbfb2 --- /dev/null +++ b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/fake/fake_testtype.go @@ -0,0 +1,197 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + json "encoding/json" + fmt "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/MixedCase/apis/example/v1" + examplev1 "k8s.io/code-generator/examples/MixedCase/applyconfiguration/example/v1" +) + +// FakeTestTypes implements TestTypeInterface +type FakeTestTypes struct { + Fake *FakeExampleV1 + ns string +} + +var testtypesResource = v1.SchemeGroupVersion.WithResource("testtypes") + +var testtypesKind = v1.SchemeGroupVersion.WithKind("TestType") + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewGetActionWithOptions(testtypesResource, c.ns, name, options), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *FakeTestTypes) List(ctx context.Context, opts metav1.ListOptions) (result *v1.TestTypeList, err error) { + emptyResult := &v1.TestTypeList{} + obj, err := c.Fake. + Invokes(testing.NewListActionWithOptions(testtypesResource, testtypesKind, c.ns, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1.TestTypeList{ListMeta: obj.(*v1.TestTypeList).ListMeta} + for _, item := range obj.(*v1.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchActionWithOptions(testtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Create(ctx context.Context, testType *v1.TestType, opts metav1.CreateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewCreateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Update(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTestTypes) UpdateStatus(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceActionWithOptions(testtypesResource, "status", c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *FakeTestTypes) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(testtypesResource, c.ns, name, opts), &v1.TestType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTestTypes) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + action := testing.NewDeleteCollectionActionWithOptions(testtypesResource, c.ns, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1.TestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched testType. +func (c *FakeTestTypes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied testType. +func (c *FakeTestTypes) Apply(ctx context.Context, testType *examplev1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.TestType, err error) { + if testType == nil { + return nil, fmt.Errorf("testType provided to Apply must not be nil") + } + data, err := json.Marshal(testType) + if err != nil { + return nil, err + } + name := testType.Name + if name == nil { + return nil, fmt.Errorf("testType.Name must be provided to Apply") + } + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeTestTypes) ApplyStatus(ctx context.Context, testType *examplev1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.TestType, err error) { + if testType == nil { + return nil, fmt.Errorf("testType provided to Apply must not be nil") + } + data, err := json.Marshal(testType) + if err != nil { + return nil, err + } + name := testType.Name + if name == nil { + return nil, fmt.Errorf("testType.Name must be provided to Apply") + } + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions(), "status"), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} diff --git a/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/generated_expansion.go b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/generated_expansion.go new file mode 100644 index 000000000..3059734a9 --- /dev/null +++ b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/generated_expansion.go @@ -0,0 +1,23 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type ClusterTestTypeExpansion interface{} + +type TestTypeExpansion interface{} diff --git a/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/testtype.go b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/testtype.go new file mode 100644 index 000000000..7962b507e --- /dev/null +++ b/code-generator/examples/MixedCase/clientset/versioned/typed/example/v1/testtype.go @@ -0,0 +1,73 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + examplev1 "k8s.io/code-generator/examples/MixedCase/apis/example/v1" + applyconfigurationexamplev1 "k8s.io/code-generator/examples/MixedCase/applyconfiguration/example/v1" + scheme "k8s.io/code-generator/examples/MixedCase/clientset/versioned/scheme" +) + +// TestTypesGetter has a method to return a TestTypeInterface. +// A group's client should implement this interface. +type TestTypesGetter interface { + TestTypes(namespace string) TestTypeInterface +} + +// TestTypeInterface has methods to work with TestType resources. +type TestTypeInterface interface { + Create(ctx context.Context, testType *examplev1.TestType, opts metav1.CreateOptions) (*examplev1.TestType, error) + Update(ctx context.Context, testType *examplev1.TestType, opts metav1.UpdateOptions) (*examplev1.TestType, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, testType *examplev1.TestType, opts metav1.UpdateOptions) (*examplev1.TestType, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*examplev1.TestType, error) + List(ctx context.Context, opts metav1.ListOptions) (*examplev1.TestTypeList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *examplev1.TestType, err error) + Apply(ctx context.Context, testType *applyconfigurationexamplev1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *examplev1.TestType, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, testType *applyconfigurationexamplev1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *examplev1.TestType, err error) + TestTypeExpansion +} + +// testTypes implements TestTypeInterface +type testTypes struct { + *gentype.ClientWithListAndApply[*examplev1.TestType, *examplev1.TestTypeList, *applyconfigurationexamplev1.TestTypeApplyConfiguration] +} + +// newTestTypes returns a TestTypes +func newTestTypes(c *ExampleV1Client, namespace string) *testTypes { + return &testTypes{ + gentype.NewClientWithListAndApply[*examplev1.TestType, *examplev1.TestTypeList, *applyconfigurationexamplev1.TestTypeApplyConfiguration]( + "testtypes", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *examplev1.TestType { return &examplev1.TestType{} }, + func() *examplev1.TestTypeList { return &examplev1.TestTypeList{} }), + } +} diff --git a/code-generator/examples/MixedCase/informers/externalversions/example/interface.go b/code-generator/examples/MixedCase/informers/externalversions/example/interface.go new file mode 100644 index 000000000..1766c025b --- /dev/null +++ b/code-generator/examples/MixedCase/informers/externalversions/example/interface.go @@ -0,0 +1,46 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package example + +import ( + v1 "k8s.io/code-generator/examples/MixedCase/informers/externalversions/example/v1" + internalinterfaces "k8s.io/code-generator/examples/MixedCase/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/code-generator/examples/MixedCase/informers/externalversions/example/v1/clustertesttype.go b/code-generator/examples/MixedCase/informers/externalversions/example/v1/clustertesttype.go new file mode 100644 index 000000000..87598ffaa --- /dev/null +++ b/code-generator/examples/MixedCase/informers/externalversions/example/v1/clustertesttype.go @@ -0,0 +1,89 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + apisexamplev1 "k8s.io/code-generator/examples/MixedCase/apis/example/v1" + versioned "k8s.io/code-generator/examples/MixedCase/clientset/versioned" + internalinterfaces "k8s.io/code-generator/examples/MixedCase/informers/externalversions/internalinterfaces" + examplev1 "k8s.io/code-generator/examples/MixedCase/listers/example/v1" +) + +// ClusterTestTypeInformer provides access to a shared informer and lister for +// ClusterTestTypes. +type ClusterTestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() examplev1.ClusterTestTypeLister +} + +type clusterTestTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewClusterTestTypeInformer constructs a new informer for ClusterTestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewClusterTestTypeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredClusterTestTypeInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredClusterTestTypeInformer constructs a new informer for ClusterTestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredClusterTestTypeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().ClusterTestTypes().List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().ClusterTestTypes().Watch(context.TODO(), options) + }, + }, + &apisexamplev1.ClusterTestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *clusterTestTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredClusterTestTypeInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *clusterTestTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apisexamplev1.ClusterTestType{}, f.defaultInformer) +} + +func (f *clusterTestTypeInformer) Lister() examplev1.ClusterTestTypeLister { + return examplev1.NewClusterTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/code-generator/examples/MixedCase/informers/externalversions/example/v1/interface.go b/code-generator/examples/MixedCase/informers/externalversions/example/v1/interface.go new file mode 100644 index 000000000..e12277e0d --- /dev/null +++ b/code-generator/examples/MixedCase/informers/externalversions/example/v1/interface.go @@ -0,0 +1,52 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "k8s.io/code-generator/examples/MixedCase/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // ClusterTestTypes returns a ClusterTestTypeInformer. + ClusterTestTypes() ClusterTestTypeInformer + // TestTypes returns a TestTypeInformer. + TestTypes() TestTypeInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// ClusterTestTypes returns a ClusterTestTypeInformer. +func (v *version) ClusterTestTypes() ClusterTestTypeInformer { + return &clusterTestTypeInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + +// TestTypes returns a TestTypeInformer. +func (v *version) TestTypes() TestTypeInformer { + return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/code-generator/examples/MixedCase/informers/externalversions/example/v1/testtype.go b/code-generator/examples/MixedCase/informers/externalversions/example/v1/testtype.go new file mode 100644 index 000000000..d23095a36 --- /dev/null +++ b/code-generator/examples/MixedCase/informers/externalversions/example/v1/testtype.go @@ -0,0 +1,90 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + apisexamplev1 "k8s.io/code-generator/examples/MixedCase/apis/example/v1" + versioned "k8s.io/code-generator/examples/MixedCase/clientset/versioned" + internalinterfaces "k8s.io/code-generator/examples/MixedCase/informers/externalversions/internalinterfaces" + examplev1 "k8s.io/code-generator/examples/MixedCase/listers/example/v1" +) + +// TestTypeInformer provides access to a shared informer and lister for +// TestTypes. +type TestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() examplev1.TestTypeLister +} + +type testTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().TestTypes(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().TestTypes(namespace).Watch(context.TODO(), options) + }, + }, + &apisexamplev1.TestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *testTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apisexamplev1.TestType{}, f.defaultInformer) +} + +func (f *testTypeInformer) Lister() examplev1.TestTypeLister { + return examplev1.NewTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/code-generator/examples/MixedCase/informers/externalversions/factory.go b/code-generator/examples/MixedCase/informers/externalversions/factory.go new file mode 100644 index 000000000..4628bbb86 --- /dev/null +++ b/code-generator/examples/MixedCase/informers/externalversions/factory.go @@ -0,0 +1,262 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + versioned "k8s.io/code-generator/examples/MixedCase/clientset/versioned" + example "k8s.io/code-generator/examples/MixedCase/informers/externalversions/example" + internalinterfaces "k8s.io/code-generator/examples/MixedCase/informers/externalversions/internalinterfaces" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + transform cache.TransformFunc + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool + // wg tracks how many goroutines were started. + wg sync.WaitGroup + // shuttingDown is true when Shutdown has been called. It may still be running + // because it needs to wait for goroutines. + shuttingDown bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// WithTransform sets a transform on all informers. +func WithTransform(transform cache.TransformFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.transform = transform + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + if f.shuttingDown { + return + } + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + f.wg.Add(1) + // We need a new variable in each loop iteration, + // otherwise the goroutine would use the loop variable + // and that keeps changing. + informer := informer + go func() { + defer f.wg.Done() + informer.Run(stopCh) + }() + f.startedInformers[informerType] = true + } + } +} + +func (f *sharedInformerFactory) Shutdown() { + f.lock.Lock() + f.shuttingDown = true + f.lock.Unlock() + + // Will return immediately if there is nothing to wait for. + f.wg.Wait() +} + +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + informer.SetTransform(f.transform) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +// +// It is typically used like this: +// +// ctx, cancel := context.Background() +// defer cancel() +// factory := NewSharedInformerFactory(client, resyncPeriod) +// defer factory.WaitForStop() // Returns immediately if nothing was started. +// genericInformer := factory.ForResource(resource) +// typedInformer := factory.SomeAPIGroup().V1().SomeType() +// factory.Start(ctx.Done()) // Start processing these informers. +// synced := factory.WaitForCacheSync(ctx.Done()) +// for v, ok := range synced { +// if !ok { +// fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v) +// return +// } +// } +// +// // Creating informers can also be created after Start, but then +// // Start must be called again: +// anotherGenericInformer := factory.ForResource(resource) +// factory.Start(ctx.Done()) +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + + // Start initializes all requested informers. They are handled in goroutines + // which run until the stop channel gets closed. + // Warning: Start does not block. When run in a go-routine, it will race with a later WaitForCacheSync. + Start(stopCh <-chan struct{}) + + // Shutdown marks a factory as shutting down. At that point no new + // informers can be started anymore and Start will return without + // doing anything. + // + // In addition, Shutdown blocks until all goroutines have terminated. For that + // to happen, the close channel(s) that they were started with must be closed, + // either before Shutdown gets called or while it is waiting. + // + // Shutdown may be called multiple times, even concurrently. All such calls will + // block until all goroutines have terminated. + Shutdown() + + // WaitForCacheSync blocks until all started informers' caches were synced + // or the stop channel gets closed. + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + // ForResource gives generic access to a shared informer of the matching type. + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + + // InformerFor returns the SharedIndexInformer for obj using an internal + // client. + InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer + + Example() example.Interface +} + +func (f *sharedInformerFactory) Example() example.Interface { + return example.New(f, f.namespace, f.tweakListOptions) +} diff --git a/code-generator/examples/MixedCase/informers/externalversions/generic.go b/code-generator/examples/MixedCase/informers/externalversions/generic.go new file mode 100644 index 000000000..ff86f38e4 --- /dev/null +++ b/code-generator/examples/MixedCase/informers/externalversions/generic.go @@ -0,0 +1,64 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + fmt "fmt" + + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + v1 "k8s.io/code-generator/examples/MixedCase/apis/example/v1" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=example.crd.code-generator.k8s.io, Version=v1 + case v1.SchemeGroupVersion.WithResource("clustertesttypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Example().V1().ClusterTestTypes().Informer()}, nil + case v1.SchemeGroupVersion.WithResource("testtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Example().V1().TestTypes().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/code-generator/examples/MixedCase/informers/externalversions/internalinterfaces/factory_interfaces.go b/code-generator/examples/MixedCase/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 000000000..2576a2ed1 --- /dev/null +++ b/code-generator/examples/MixedCase/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" + versioned "k8s.io/code-generator/examples/MixedCase/clientset/versioned" +) + +// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +// TweakListOptionsFunc is a function that transforms a v1.ListOptions. +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/code-generator/examples/MixedCase/listers/example/v1/clustertesttype.go b/code-generator/examples/MixedCase/listers/example/v1/clustertesttype.go new file mode 100644 index 000000000..a345523c3 --- /dev/null +++ b/code-generator/examples/MixedCase/listers/example/v1/clustertesttype.go @@ -0,0 +1,48 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" + examplev1 "k8s.io/code-generator/examples/MixedCase/apis/example/v1" +) + +// ClusterTestTypeLister helps list ClusterTestTypes. +// All objects returned here must be treated as read-only. +type ClusterTestTypeLister interface { + // List lists all ClusterTestTypes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*examplev1.ClusterTestType, err error) + // Get retrieves the ClusterTestType from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*examplev1.ClusterTestType, error) + ClusterTestTypeListerExpansion +} + +// clusterTestTypeLister implements the ClusterTestTypeLister interface. +type clusterTestTypeLister struct { + listers.ResourceIndexer[*examplev1.ClusterTestType] +} + +// NewClusterTestTypeLister returns a new ClusterTestTypeLister. +func NewClusterTestTypeLister(indexer cache.Indexer) ClusterTestTypeLister { + return &clusterTestTypeLister{listers.New[*examplev1.ClusterTestType](indexer, examplev1.Resource("clustertesttype"))} +} diff --git a/code-generator/examples/MixedCase/listers/example/v1/expansion_generated.go b/code-generator/examples/MixedCase/listers/example/v1/expansion_generated.go new file mode 100644 index 000000000..2681a29f4 --- /dev/null +++ b/code-generator/examples/MixedCase/listers/example/v1/expansion_generated.go @@ -0,0 +1,31 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// ClusterTestTypeListerExpansion allows custom methods to be added to +// ClusterTestTypeLister. +type ClusterTestTypeListerExpansion interface{} + +// TestTypeListerExpansion allows custom methods to be added to +// TestTypeLister. +type TestTypeListerExpansion interface{} + +// TestTypeNamespaceListerExpansion allows custom methods to be added to +// TestTypeNamespaceLister. +type TestTypeNamespaceListerExpansion interface{} diff --git a/code-generator/examples/MixedCase/listers/example/v1/testtype.go b/code-generator/examples/MixedCase/listers/example/v1/testtype.go new file mode 100644 index 000000000..d9ded5532 --- /dev/null +++ b/code-generator/examples/MixedCase/listers/example/v1/testtype.go @@ -0,0 +1,70 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" + examplev1 "k8s.io/code-generator/examples/MixedCase/apis/example/v1" +) + +// TestTypeLister helps list TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeLister interface { + // List lists all TestTypes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*examplev1.TestType, err error) + // TestTypes returns an object that can list and get TestTypes. + TestTypes(namespace string) TestTypeNamespaceLister + TestTypeListerExpansion +} + +// testTypeLister implements the TestTypeLister interface. +type testTypeLister struct { + listers.ResourceIndexer[*examplev1.TestType] +} + +// NewTestTypeLister returns a new TestTypeLister. +func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { + return &testTypeLister{listers.New[*examplev1.TestType](indexer, examplev1.Resource("testtype"))} +} + +// TestTypes returns an object that can list and get TestTypes. +func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { + return testTypeNamespaceLister{listers.NewNamespaced[*examplev1.TestType](s.ResourceIndexer, namespace)} +} + +// TestTypeNamespaceLister helps list and get TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeNamespaceLister interface { + // List lists all TestTypes in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*examplev1.TestType, err error) + // Get retrieves the TestType from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*examplev1.TestType, error) + TestTypeNamespaceListerExpansion +} + +// testTypeNamespaceLister implements the TestTypeNamespaceLister +// interface. +type testTypeNamespaceLister struct { + listers.ResourceIndexer[*examplev1.TestType] +} diff --git a/code-generator/examples/apiserver/apis/core/doc.go b/code-generator/examples/apiserver/apis/core/doc.go new file mode 100644 index 000000000..da7673780 --- /dev/null +++ b/code-generator/examples/apiserver/apis/core/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2024 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package +// +groupName= + +package core // import "k8s.io/code-generator/examples/apiserver/apis/core" diff --git a/code-generator/examples/apiserver/apis/core/install/install.go b/code-generator/examples/apiserver/apis/core/install/install.go new file mode 100644 index 000000000..c1b6d2d5c --- /dev/null +++ b/code-generator/examples/apiserver/apis/core/install/install.go @@ -0,0 +1,33 @@ +/* +Copyright 2024 The Kubernetes 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 install installs the experimental API group, making it available as +// an option to all of the API encoding/decoding machinery. +package install + +import ( + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/code-generator/examples/apiserver/apis/core" + "k8s.io/code-generator/examples/apiserver/apis/core/v1" +) + +// Install registers the API group and adds types to a scheme +func Install(scheme *runtime.Scheme) { + utilruntime.Must(core.AddToScheme(scheme)) + utilruntime.Must(v1.AddToScheme(scheme)) + utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion)) +} diff --git a/code-generator/examples/apiserver/apis/core/register.go b/code-generator/examples/apiserver/apis/core/register.go new file mode 100644 index 000000000..9e2cd292a --- /dev/null +++ b/code-generator/examples/apiserver/apis/core/register.go @@ -0,0 +1,45 @@ +/* +Copyright 2024 The Kubernetes 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 core + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Version: runtime.APIVersionInternal} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion) + return nil +} diff --git a/code-generator/examples/apiserver/apis/core/types.go b/code-generator/examples/apiserver/apis/core/types.go new file mode 100644 index 000000000..9ad4579cd --- /dev/null +++ b/code-generator/examples/apiserver/apis/core/types.go @@ -0,0 +1,47 @@ +/* +Copyright 2024 The Kubernetes 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 core + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + // +optional + Status TestTypeStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + Items []TestType +} + +type TestTypeStatus struct { + Blah string +} diff --git a/code-generator/examples/apiserver/apis/core/v1/doc.go b/code-generator/examples/apiserver/apis/core/v1/doc.go new file mode 100644 index 000000000..0de0bdda6 --- /dev/null +++ b/code-generator/examples/apiserver/apis/core/v1/doc.go @@ -0,0 +1,23 @@ +/* +Copyright 2024 The Kubernetes 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. +*/ + +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package +// +k8s:defaulter-gen=TypeMeta +// +k8s:conversion-gen=k8s.io/code-generator/examples/apiserver/apis/core +// +groupName= + +package v1 // import "k8s.io/code-generator/examples/apiserver/apis/core/v1" diff --git a/code-generator/examples/apiserver/apis/core/v1/register.go b/code-generator/examples/apiserver/apis/core/v1/register.go new file mode 100644 index 000000000..0bfc241a4 --- /dev/null +++ b/code-generator/examples/apiserver/apis/core/v1/register.go @@ -0,0 +1,59 @@ +/* +Copyright 2024 The Kubernetes 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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.apiserver.code-generator.k8s.io", Version: "v1"} + +var ( + // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion, + &metav1.Status{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/code-generator/examples/apiserver/apis/core/v1/types.go b/code-generator/examples/apiserver/apis/core/v1/types.go new file mode 100644 index 000000000..5a9c0b9a7 --- /dev/null +++ b/code-generator/examples/apiserver/apis/core/v1/types.go @@ -0,0 +1,47 @@ +/* +Copyright 2024 The Kubernetes 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 v1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status TestTypeStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []TestType `json:"items"` +} + +type TestTypeStatus struct { + Blah string `json:"blah"` +} diff --git a/code-generator/examples/apiserver/apis/core/v1/zz_generated.conversion.go b/code-generator/examples/apiserver/apis/core/v1/zz_generated.conversion.go new file mode 100644 index 000000000..59219a1b3 --- /dev/null +++ b/code-generator/examples/apiserver/apis/core/v1/zz_generated.conversion.go @@ -0,0 +1,138 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1 + +import ( + unsafe "unsafe" + + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + core "k8s.io/code-generator/examples/apiserver/apis/core" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*TestType)(nil), (*core.TestType)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestType_To_core_TestType(a.(*TestType), b.(*core.TestType), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.TestType)(nil), (*TestType)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_TestType_To_v1_TestType(a.(*core.TestType), b.(*TestType), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*TestTypeList)(nil), (*core.TestTypeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestTypeList_To_core_TestTypeList(a.(*TestTypeList), b.(*core.TestTypeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.TestTypeList)(nil), (*TestTypeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_TestTypeList_To_v1_TestTypeList(a.(*core.TestTypeList), b.(*TestTypeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*TestTypeStatus)(nil), (*core.TestTypeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestTypeStatus_To_core_TestTypeStatus(a.(*TestTypeStatus), b.(*core.TestTypeStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*core.TestTypeStatus)(nil), (*TestTypeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_core_TestTypeStatus_To_v1_TestTypeStatus(a.(*core.TestTypeStatus), b.(*TestTypeStatus), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1_TestType_To_core_TestType(in *TestType, out *core.TestType, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_TestTypeStatus_To_core_TestTypeStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1_TestType_To_core_TestType is an autogenerated conversion function. +func Convert_v1_TestType_To_core_TestType(in *TestType, out *core.TestType, s conversion.Scope) error { + return autoConvert_v1_TestType_To_core_TestType(in, out, s) +} + +func autoConvert_core_TestType_To_v1_TestType(in *core.TestType, out *TestType, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_core_TestTypeStatus_To_v1_TestTypeStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_core_TestType_To_v1_TestType is an autogenerated conversion function. +func Convert_core_TestType_To_v1_TestType(in *core.TestType, out *TestType, s conversion.Scope) error { + return autoConvert_core_TestType_To_v1_TestType(in, out, s) +} + +func autoConvert_v1_TestTypeList_To_core_TestTypeList(in *TestTypeList, out *core.TestTypeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]core.TestType)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1_TestTypeList_To_core_TestTypeList is an autogenerated conversion function. +func Convert_v1_TestTypeList_To_core_TestTypeList(in *TestTypeList, out *core.TestTypeList, s conversion.Scope) error { + return autoConvert_v1_TestTypeList_To_core_TestTypeList(in, out, s) +} + +func autoConvert_core_TestTypeList_To_v1_TestTypeList(in *core.TestTypeList, out *TestTypeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]TestType)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_core_TestTypeList_To_v1_TestTypeList is an autogenerated conversion function. +func Convert_core_TestTypeList_To_v1_TestTypeList(in *core.TestTypeList, out *TestTypeList, s conversion.Scope) error { + return autoConvert_core_TestTypeList_To_v1_TestTypeList(in, out, s) +} + +func autoConvert_v1_TestTypeStatus_To_core_TestTypeStatus(in *TestTypeStatus, out *core.TestTypeStatus, s conversion.Scope) error { + out.Blah = in.Blah + return nil +} + +// Convert_v1_TestTypeStatus_To_core_TestTypeStatus is an autogenerated conversion function. +func Convert_v1_TestTypeStatus_To_core_TestTypeStatus(in *TestTypeStatus, out *core.TestTypeStatus, s conversion.Scope) error { + return autoConvert_v1_TestTypeStatus_To_core_TestTypeStatus(in, out, s) +} + +func autoConvert_core_TestTypeStatus_To_v1_TestTypeStatus(in *core.TestTypeStatus, out *TestTypeStatus, s conversion.Scope) error { + out.Blah = in.Blah + return nil +} + +// Convert_core_TestTypeStatus_To_v1_TestTypeStatus is an autogenerated conversion function. +func Convert_core_TestTypeStatus_To_v1_TestTypeStatus(in *core.TestTypeStatus, out *TestTypeStatus, s conversion.Scope) error { + return autoConvert_core_TestTypeStatus_To_v1_TestTypeStatus(in, out, s) +} diff --git a/code-generator/examples/apiserver/apis/core/v1/zz_generated.deepcopy.go b/code-generator/examples/apiserver/apis/core/v1/zz_generated.deepcopy.go new file mode 100644 index 000000000..d87f706f7 --- /dev/null +++ b/code-generator/examples/apiserver/apis/core/v1/zz_generated.deepcopy.go @@ -0,0 +1,102 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/examples/apiserver/apis/core/v1/zz_generated.defaults.go b/code-generator/examples/apiserver/apis/core/v1/zz_generated.defaults.go new file mode 100644 index 000000000..dac177e93 --- /dev/null +++ b/code-generator/examples/apiserver/apis/core/v1/zz_generated.defaults.go @@ -0,0 +1,33 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/code-generator/examples/apiserver/apis/core/zz_generated.deepcopy.go b/code-generator/examples/apiserver/apis/core/zz_generated.deepcopy.go new file mode 100644 index 000000000..4e5954211 --- /dev/null +++ b/code-generator/examples/apiserver/apis/core/zz_generated.deepcopy.go @@ -0,0 +1,102 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package core + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/examples/apiserver/apis/example/doc.go b/code-generator/examples/apiserver/apis/example/doc.go new file mode 100644 index 000000000..97d06e690 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2015 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package +// +groupName=example.apiserver.code-generator.k8s.io + +package example // import "k8s.io/code-generator/examples/apiserver/apis/example" diff --git a/code-generator/examples/apiserver/apis/example/install/install.go b/code-generator/examples/apiserver/apis/example/install/install.go new file mode 100644 index 000000000..80b583b89 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example/install/install.go @@ -0,0 +1,33 @@ +/* +Copyright 2015 The Kubernetes 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 install installs the experimental API group, making it available as +// an option to all of the API encoding/decoding machinery. +package install + +import ( + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/code-generator/examples/apiserver/apis/example" + "k8s.io/code-generator/examples/apiserver/apis/example/v1" +) + +// Install registers the API group and adds types to a scheme +func Install(scheme *runtime.Scheme) { + utilruntime.Must(example.AddToScheme(scheme)) + utilruntime.Must(v1.AddToScheme(scheme)) + utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion)) +} diff --git a/code-generator/examples/apiserver/apis/example/register.go b/code-generator/examples/apiserver/apis/example/register.go new file mode 100644 index 000000000..da397b524 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example/register.go @@ -0,0 +1,45 @@ +/* +Copyright 2015 The Kubernetes 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 example + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.api.code-generator.k8s.io", Version: runtime.APIVersionInternal} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion) + return nil +} diff --git a/code-generator/examples/apiserver/apis/example/types.go b/code-generator/examples/apiserver/apis/example/types.go new file mode 100644 index 000000000..8f3dbb553 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example/types.go @@ -0,0 +1,47 @@ +/* +Copyright 2015 The Kubernetes 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 example + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + // +optional + Status TestTypeStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + Items []TestType +} + +type TestTypeStatus struct { + Blah string +} diff --git a/code-generator/examples/apiserver/apis/example/v1/doc.go b/code-generator/examples/apiserver/apis/example/v1/doc.go new file mode 100644 index 000000000..9de47d160 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example/v1/doc.go @@ -0,0 +1,23 @@ +/* +Copyright 2016 The Kubernetes 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. +*/ + +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package +// +k8s:defaulter-gen=TypeMeta +// +k8s:conversion-gen=k8s.io/code-generator/examples/apiserver/apis/example +// +groupName=example.apiserver.code-generator.k8s.io + +package v1 // import "k8s.io/code-generator/examples/apiserver/apis/example/v1" diff --git a/code-generator/examples/apiserver/apis/example/v1/register.go b/code-generator/examples/apiserver/apis/example/v1/register.go new file mode 100644 index 000000000..c99619d7a --- /dev/null +++ b/code-generator/examples/apiserver/apis/example/v1/register.go @@ -0,0 +1,59 @@ +/* +Copyright 2015 The Kubernetes 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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.apiserver.code-generator.k8s.io", Version: "v1"} + +var ( + // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion, + &metav1.Status{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/code-generator/examples/apiserver/apis/example/v1/types.go b/code-generator/examples/apiserver/apis/example/v1/types.go new file mode 100644 index 000000000..24a1a348c --- /dev/null +++ b/code-generator/examples/apiserver/apis/example/v1/types.go @@ -0,0 +1,47 @@ +/* +Copyright 2015 The Kubernetes 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 v1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status TestTypeStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []TestType `json:"items"` +} + +type TestTypeStatus struct { + Blah string `json:"blah"` +} diff --git a/code-generator/examples/apiserver/apis/example/v1/zz_generated.conversion.go b/code-generator/examples/apiserver/apis/example/v1/zz_generated.conversion.go new file mode 100644 index 000000000..ac03143b4 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example/v1/zz_generated.conversion.go @@ -0,0 +1,138 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1 + +import ( + unsafe "unsafe" + + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + example "k8s.io/code-generator/examples/apiserver/apis/example" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*TestType)(nil), (*example.TestType)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestType_To_example_TestType(a.(*TestType), b.(*example.TestType), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*example.TestType)(nil), (*TestType)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_example_TestType_To_v1_TestType(a.(*example.TestType), b.(*TestType), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*TestTypeList)(nil), (*example.TestTypeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestTypeList_To_example_TestTypeList(a.(*TestTypeList), b.(*example.TestTypeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*example.TestTypeList)(nil), (*TestTypeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_example_TestTypeList_To_v1_TestTypeList(a.(*example.TestTypeList), b.(*TestTypeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*TestTypeStatus)(nil), (*example.TestTypeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestTypeStatus_To_example_TestTypeStatus(a.(*TestTypeStatus), b.(*example.TestTypeStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*example.TestTypeStatus)(nil), (*TestTypeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_example_TestTypeStatus_To_v1_TestTypeStatus(a.(*example.TestTypeStatus), b.(*TestTypeStatus), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1_TestType_To_example_TestType(in *TestType, out *example.TestType, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_TestTypeStatus_To_example_TestTypeStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1_TestType_To_example_TestType is an autogenerated conversion function. +func Convert_v1_TestType_To_example_TestType(in *TestType, out *example.TestType, s conversion.Scope) error { + return autoConvert_v1_TestType_To_example_TestType(in, out, s) +} + +func autoConvert_example_TestType_To_v1_TestType(in *example.TestType, out *TestType, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_example_TestTypeStatus_To_v1_TestTypeStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_example_TestType_To_v1_TestType is an autogenerated conversion function. +func Convert_example_TestType_To_v1_TestType(in *example.TestType, out *TestType, s conversion.Scope) error { + return autoConvert_example_TestType_To_v1_TestType(in, out, s) +} + +func autoConvert_v1_TestTypeList_To_example_TestTypeList(in *TestTypeList, out *example.TestTypeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]example.TestType)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1_TestTypeList_To_example_TestTypeList is an autogenerated conversion function. +func Convert_v1_TestTypeList_To_example_TestTypeList(in *TestTypeList, out *example.TestTypeList, s conversion.Scope) error { + return autoConvert_v1_TestTypeList_To_example_TestTypeList(in, out, s) +} + +func autoConvert_example_TestTypeList_To_v1_TestTypeList(in *example.TestTypeList, out *TestTypeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]TestType)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_example_TestTypeList_To_v1_TestTypeList is an autogenerated conversion function. +func Convert_example_TestTypeList_To_v1_TestTypeList(in *example.TestTypeList, out *TestTypeList, s conversion.Scope) error { + return autoConvert_example_TestTypeList_To_v1_TestTypeList(in, out, s) +} + +func autoConvert_v1_TestTypeStatus_To_example_TestTypeStatus(in *TestTypeStatus, out *example.TestTypeStatus, s conversion.Scope) error { + out.Blah = in.Blah + return nil +} + +// Convert_v1_TestTypeStatus_To_example_TestTypeStatus is an autogenerated conversion function. +func Convert_v1_TestTypeStatus_To_example_TestTypeStatus(in *TestTypeStatus, out *example.TestTypeStatus, s conversion.Scope) error { + return autoConvert_v1_TestTypeStatus_To_example_TestTypeStatus(in, out, s) +} + +func autoConvert_example_TestTypeStatus_To_v1_TestTypeStatus(in *example.TestTypeStatus, out *TestTypeStatus, s conversion.Scope) error { + out.Blah = in.Blah + return nil +} + +// Convert_example_TestTypeStatus_To_v1_TestTypeStatus is an autogenerated conversion function. +func Convert_example_TestTypeStatus_To_v1_TestTypeStatus(in *example.TestTypeStatus, out *TestTypeStatus, s conversion.Scope) error { + return autoConvert_example_TestTypeStatus_To_v1_TestTypeStatus(in, out, s) +} diff --git a/code-generator/examples/apiserver/apis/example/v1/zz_generated.deepcopy.go b/code-generator/examples/apiserver/apis/example/v1/zz_generated.deepcopy.go new file mode 100644 index 000000000..d87f706f7 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example/v1/zz_generated.deepcopy.go @@ -0,0 +1,102 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/examples/apiserver/apis/example/v1/zz_generated.defaults.go b/code-generator/examples/apiserver/apis/example/v1/zz_generated.defaults.go new file mode 100644 index 000000000..dac177e93 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example/v1/zz_generated.defaults.go @@ -0,0 +1,33 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/code-generator/examples/apiserver/apis/example/zz_generated.deepcopy.go b/code-generator/examples/apiserver/apis/example/zz_generated.deepcopy.go new file mode 100644 index 000000000..650077277 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example/zz_generated.deepcopy.go @@ -0,0 +1,102 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package example + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/examples/apiserver/apis/example2/doc.go b/code-generator/examples/apiserver/apis/example2/doc.go new file mode 100644 index 000000000..c4a408eac --- /dev/null +++ b/code-generator/examples/apiserver/apis/example2/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2015 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package +// +groupName=example.test.apiserver.code-generator.k8s.io +// +groupGoName=SecondExample + +package example2 // import "k8s.io/code-generator/examples/apiserver/apis/example2" diff --git a/code-generator/examples/apiserver/apis/example2/install/install.go b/code-generator/examples/apiserver/apis/example2/install/install.go new file mode 100644 index 000000000..97e6d1081 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example2/install/install.go @@ -0,0 +1,33 @@ +/* +Copyright 2015 The Kubernetes 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 install installs the experimental API group, making it available as +// an option to all of the API encoding/decoding machinery. +package install + +import ( + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + "k8s.io/code-generator/examples/apiserver/apis/example2" + "k8s.io/code-generator/examples/apiserver/apis/example2/v1" +) + +// Install registers the API group and adds types to a scheme +func Install(scheme *runtime.Scheme) { + utilruntime.Must(example2.AddToScheme(scheme)) + utilruntime.Must(v1.AddToScheme(scheme)) + utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion)) +} diff --git a/code-generator/examples/apiserver/apis/example2/register.go b/code-generator/examples/apiserver/apis/example2/register.go new file mode 100644 index 000000000..508565af7 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example2/register.go @@ -0,0 +1,45 @@ +/* +Copyright 2015 The Kubernetes 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 example2 + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.test.apiserver.code-generator.k8s.io", Version: runtime.APIVersionInternal} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion) + return nil +} diff --git a/code-generator/examples/apiserver/apis/example2/types.go b/code-generator/examples/apiserver/apis/example2/types.go new file mode 100644 index 000000000..3bdcf2a9a --- /dev/null +++ b/code-generator/examples/apiserver/apis/example2/types.go @@ -0,0 +1,45 @@ +/* +Copyright 2015 The Kubernetes 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 example2 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient:nonNamespaced +// +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta + metav1.ObjectMeta + Status TestTypeStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta + metav1.ListMeta + + Items []TestType +} + +type TestTypeStatus struct { + Blah string +} diff --git a/code-generator/examples/apiserver/apis/example2/v1/doc.go b/code-generator/examples/apiserver/apis/example2/v1/doc.go new file mode 100644 index 000000000..b46b07f1d --- /dev/null +++ b/code-generator/examples/apiserver/apis/example2/v1/doc.go @@ -0,0 +1,24 @@ +/* +Copyright 2016 The Kubernetes 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. +*/ + +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package +// +k8s:defaulter-gen=TypeMeta +// +groupName=example.test.apiserver.code-generator.k8s.io +// +k8s:conversion-gen=k8s.io/code-generator/examples/apiserver/apis/example2 +// +groupGoName=SecondExample + +package v1 // import "k8s.io/code-generator/examples/apiserver/apis/example2/v1" diff --git a/code-generator/examples/apiserver/apis/example2/v1/register.go b/code-generator/examples/apiserver/apis/example2/v1/register.go new file mode 100644 index 000000000..19dd0c356 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example2/v1/register.go @@ -0,0 +1,59 @@ +/* +Copyright 2015 The Kubernetes 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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.test.apiserver.code-generator.k8s.io", Version: "v1"} + +var ( + // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to api.Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion, + &metav1.Status{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/code-generator/examples/apiserver/apis/example2/v1/types.go b/code-generator/examples/apiserver/apis/example2/v1/types.go new file mode 100644 index 000000000..24a1a348c --- /dev/null +++ b/code-generator/examples/apiserver/apis/example2/v1/types.go @@ -0,0 +1,47 @@ +/* +Copyright 2015 The Kubernetes 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 v1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status TestTypeStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []TestType `json:"items"` +} + +type TestTypeStatus struct { + Blah string `json:"blah"` +} diff --git a/code-generator/examples/apiserver/apis/example2/v1/zz_generated.conversion.go b/code-generator/examples/apiserver/apis/example2/v1/zz_generated.conversion.go new file mode 100644 index 000000000..efff2d34b --- /dev/null +++ b/code-generator/examples/apiserver/apis/example2/v1/zz_generated.conversion.go @@ -0,0 +1,138 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1 + +import ( + unsafe "unsafe" + + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + example2 "k8s.io/code-generator/examples/apiserver/apis/example2" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*TestType)(nil), (*example2.TestType)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestType_To_example2_TestType(a.(*TestType), b.(*example2.TestType), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*example2.TestType)(nil), (*TestType)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_example2_TestType_To_v1_TestType(a.(*example2.TestType), b.(*TestType), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*TestTypeList)(nil), (*example2.TestTypeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestTypeList_To_example2_TestTypeList(a.(*TestTypeList), b.(*example2.TestTypeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*example2.TestTypeList)(nil), (*TestTypeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_example2_TestTypeList_To_v1_TestTypeList(a.(*example2.TestTypeList), b.(*TestTypeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*TestTypeStatus)(nil), (*example2.TestTypeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestTypeStatus_To_example2_TestTypeStatus(a.(*TestTypeStatus), b.(*example2.TestTypeStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*example2.TestTypeStatus)(nil), (*TestTypeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_example2_TestTypeStatus_To_v1_TestTypeStatus(a.(*example2.TestTypeStatus), b.(*TestTypeStatus), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1_TestType_To_example2_TestType(in *TestType, out *example2.TestType, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_TestTypeStatus_To_example2_TestTypeStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1_TestType_To_example2_TestType is an autogenerated conversion function. +func Convert_v1_TestType_To_example2_TestType(in *TestType, out *example2.TestType, s conversion.Scope) error { + return autoConvert_v1_TestType_To_example2_TestType(in, out, s) +} + +func autoConvert_example2_TestType_To_v1_TestType(in *example2.TestType, out *TestType, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_example2_TestTypeStatus_To_v1_TestTypeStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_example2_TestType_To_v1_TestType is an autogenerated conversion function. +func Convert_example2_TestType_To_v1_TestType(in *example2.TestType, out *TestType, s conversion.Scope) error { + return autoConvert_example2_TestType_To_v1_TestType(in, out, s) +} + +func autoConvert_v1_TestTypeList_To_example2_TestTypeList(in *TestTypeList, out *example2.TestTypeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]example2.TestType)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1_TestTypeList_To_example2_TestTypeList is an autogenerated conversion function. +func Convert_v1_TestTypeList_To_example2_TestTypeList(in *TestTypeList, out *example2.TestTypeList, s conversion.Scope) error { + return autoConvert_v1_TestTypeList_To_example2_TestTypeList(in, out, s) +} + +func autoConvert_example2_TestTypeList_To_v1_TestTypeList(in *example2.TestTypeList, out *TestTypeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]TestType)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_example2_TestTypeList_To_v1_TestTypeList is an autogenerated conversion function. +func Convert_example2_TestTypeList_To_v1_TestTypeList(in *example2.TestTypeList, out *TestTypeList, s conversion.Scope) error { + return autoConvert_example2_TestTypeList_To_v1_TestTypeList(in, out, s) +} + +func autoConvert_v1_TestTypeStatus_To_example2_TestTypeStatus(in *TestTypeStatus, out *example2.TestTypeStatus, s conversion.Scope) error { + out.Blah = in.Blah + return nil +} + +// Convert_v1_TestTypeStatus_To_example2_TestTypeStatus is an autogenerated conversion function. +func Convert_v1_TestTypeStatus_To_example2_TestTypeStatus(in *TestTypeStatus, out *example2.TestTypeStatus, s conversion.Scope) error { + return autoConvert_v1_TestTypeStatus_To_example2_TestTypeStatus(in, out, s) +} + +func autoConvert_example2_TestTypeStatus_To_v1_TestTypeStatus(in *example2.TestTypeStatus, out *TestTypeStatus, s conversion.Scope) error { + out.Blah = in.Blah + return nil +} + +// Convert_example2_TestTypeStatus_To_v1_TestTypeStatus is an autogenerated conversion function. +func Convert_example2_TestTypeStatus_To_v1_TestTypeStatus(in *example2.TestTypeStatus, out *TestTypeStatus, s conversion.Scope) error { + return autoConvert_example2_TestTypeStatus_To_v1_TestTypeStatus(in, out, s) +} diff --git a/code-generator/examples/apiserver/apis/example2/v1/zz_generated.deepcopy.go b/code-generator/examples/apiserver/apis/example2/v1/zz_generated.deepcopy.go new file mode 100644 index 000000000..d87f706f7 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example2/v1/zz_generated.deepcopy.go @@ -0,0 +1,102 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/examples/apiserver/apis/example2/v1/zz_generated.defaults.go b/code-generator/examples/apiserver/apis/example2/v1/zz_generated.defaults.go new file mode 100644 index 000000000..dac177e93 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example2/v1/zz_generated.defaults.go @@ -0,0 +1,33 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/code-generator/examples/apiserver/apis/example2/zz_generated.deepcopy.go b/code-generator/examples/apiserver/apis/example2/zz_generated.deepcopy.go new file mode 100644 index 000000000..1fa43c462 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example2/zz_generated.deepcopy.go @@ -0,0 +1,102 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package example2 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/examples/apiserver/apis/example3.io/doc.go b/code-generator/examples/apiserver/apis/example3.io/doc.go new file mode 100644 index 000000000..f1779abe4 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example3.io/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2015 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package +// +groupName=example.dots.apiserver.code-generator.k8s.io +// +groupGoName=ThirdExample + +package example3 // import "k8s.io/code-generator/examples/apiserver/apis/example3.io" diff --git a/code-generator/examples/apiserver/apis/example3.io/install/install.go b/code-generator/examples/apiserver/apis/example3.io/install/install.go new file mode 100644 index 000000000..7305d2bbe --- /dev/null +++ b/code-generator/examples/apiserver/apis/example3.io/install/install.go @@ -0,0 +1,33 @@ +/* +Copyright 2015 The Kubernetes 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 install installs the experimental API group, making it available as +// an option to all of the API encoding/decoding machinery. +package install + +import ( + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + example3 "k8s.io/code-generator/examples/apiserver/apis/example3.io" + "k8s.io/code-generator/examples/apiserver/apis/example3.io/v1" +) + +// Install registers the API group and adds types to a scheme +func Install(scheme *runtime.Scheme) { + utilruntime.Must(example3.AddToScheme(scheme)) + utilruntime.Must(v1.AddToScheme(scheme)) + utilruntime.Must(scheme.SetVersionPriority(v1.SchemeGroupVersion)) +} diff --git a/code-generator/examples/apiserver/apis/example3.io/register.go b/code-generator/examples/apiserver/apis/example3.io/register.go new file mode 100644 index 000000000..b77b2b180 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example3.io/register.go @@ -0,0 +1,45 @@ +/* +Copyright 2015 The Kubernetes 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 example3 + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.dots.apiserver.code-generator.k8s.io", Version: runtime.APIVersionInternal} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion) + return nil +} diff --git a/code-generator/examples/apiserver/apis/example3.io/types.go b/code-generator/examples/apiserver/apis/example3.io/types.go new file mode 100644 index 000000000..a020b0af5 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example3.io/types.go @@ -0,0 +1,47 @@ +/* +Copyright 2015 The Kubernetes 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 example3 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta + // +optional + metav1.ObjectMeta + // +optional + Status TestTypeStatus +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta + // +optional + metav1.ListMeta + + Items []TestType +} + +type TestTypeStatus struct { + Blah string +} diff --git a/code-generator/examples/apiserver/apis/example3.io/v1/doc.go b/code-generator/examples/apiserver/apis/example3.io/v1/doc.go new file mode 100644 index 000000000..f6aa7bdc0 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example3.io/v1/doc.go @@ -0,0 +1,24 @@ +/* +Copyright 2016 The Kubernetes 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. +*/ + +// +k8s:openapi-gen=true +// +k8s:deepcopy-gen=package +// +k8s:defaulter-gen=TypeMeta +// +groupName=example.dots.apiserver.code-generator.k8s.io +// +k8s:conversion-gen=k8s.io/code-generator/examples/apiserver/apis/example3.io +// +groupGoName=ThirdExample + +package v1 // import "k8s.io/code-generator/examples/apiserver/apis/example3.io/v1" diff --git a/code-generator/examples/apiserver/apis/example3.io/v1/register.go b/code-generator/examples/apiserver/apis/example3.io/v1/register.go new file mode 100644 index 000000000..3e0a393f7 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example3.io/v1/register.go @@ -0,0 +1,59 @@ +/* +Copyright 2015 The Kubernetes 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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.dots.apiserver.code-generator.k8s.io", Version: "v1"} + +var ( + // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to api.Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion, + &metav1.Status{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/code-generator/examples/apiserver/apis/example3.io/v1/types.go b/code-generator/examples/apiserver/apis/example3.io/v1/types.go new file mode 100644 index 000000000..24a1a348c --- /dev/null +++ b/code-generator/examples/apiserver/apis/example3.io/v1/types.go @@ -0,0 +1,47 @@ +/* +Copyright 2015 The Kubernetes 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 v1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status TestTypeStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []TestType `json:"items"` +} + +type TestTypeStatus struct { + Blah string `json:"blah"` +} diff --git a/code-generator/examples/apiserver/apis/example3.io/v1/zz_generated.conversion.go b/code-generator/examples/apiserver/apis/example3.io/v1/zz_generated.conversion.go new file mode 100644 index 000000000..f1aecef53 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example3.io/v1/zz_generated.conversion.go @@ -0,0 +1,138 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1 + +import ( + unsafe "unsafe" + + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" + example3io "k8s.io/code-generator/examples/apiserver/apis/example3.io" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*TestType)(nil), (*example3io.TestType)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestType_To_example3io_TestType(a.(*TestType), b.(*example3io.TestType), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*example3io.TestType)(nil), (*TestType)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_example3io_TestType_To_v1_TestType(a.(*example3io.TestType), b.(*TestType), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*TestTypeList)(nil), (*example3io.TestTypeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestTypeList_To_example3io_TestTypeList(a.(*TestTypeList), b.(*example3io.TestTypeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*example3io.TestTypeList)(nil), (*TestTypeList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_example3io_TestTypeList_To_v1_TestTypeList(a.(*example3io.TestTypeList), b.(*TestTypeList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*TestTypeStatus)(nil), (*example3io.TestTypeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1_TestTypeStatus_To_example3io_TestTypeStatus(a.(*TestTypeStatus), b.(*example3io.TestTypeStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*example3io.TestTypeStatus)(nil), (*TestTypeStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_example3io_TestTypeStatus_To_v1_TestTypeStatus(a.(*example3io.TestTypeStatus), b.(*TestTypeStatus), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1_TestType_To_example3io_TestType(in *TestType, out *example3io.TestType, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1_TestTypeStatus_To_example3io_TestTypeStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1_TestType_To_example3io_TestType is an autogenerated conversion function. +func Convert_v1_TestType_To_example3io_TestType(in *TestType, out *example3io.TestType, s conversion.Scope) error { + return autoConvert_v1_TestType_To_example3io_TestType(in, out, s) +} + +func autoConvert_example3io_TestType_To_v1_TestType(in *example3io.TestType, out *TestType, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_example3io_TestTypeStatus_To_v1_TestTypeStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_example3io_TestType_To_v1_TestType is an autogenerated conversion function. +func Convert_example3io_TestType_To_v1_TestType(in *example3io.TestType, out *TestType, s conversion.Scope) error { + return autoConvert_example3io_TestType_To_v1_TestType(in, out, s) +} + +func autoConvert_v1_TestTypeList_To_example3io_TestTypeList(in *TestTypeList, out *example3io.TestTypeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]example3io.TestType)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1_TestTypeList_To_example3io_TestTypeList is an autogenerated conversion function. +func Convert_v1_TestTypeList_To_example3io_TestTypeList(in *TestTypeList, out *example3io.TestTypeList, s conversion.Scope) error { + return autoConvert_v1_TestTypeList_To_example3io_TestTypeList(in, out, s) +} + +func autoConvert_example3io_TestTypeList_To_v1_TestTypeList(in *example3io.TestTypeList, out *TestTypeList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]TestType)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_example3io_TestTypeList_To_v1_TestTypeList is an autogenerated conversion function. +func Convert_example3io_TestTypeList_To_v1_TestTypeList(in *example3io.TestTypeList, out *TestTypeList, s conversion.Scope) error { + return autoConvert_example3io_TestTypeList_To_v1_TestTypeList(in, out, s) +} + +func autoConvert_v1_TestTypeStatus_To_example3io_TestTypeStatus(in *TestTypeStatus, out *example3io.TestTypeStatus, s conversion.Scope) error { + out.Blah = in.Blah + return nil +} + +// Convert_v1_TestTypeStatus_To_example3io_TestTypeStatus is an autogenerated conversion function. +func Convert_v1_TestTypeStatus_To_example3io_TestTypeStatus(in *TestTypeStatus, out *example3io.TestTypeStatus, s conversion.Scope) error { + return autoConvert_v1_TestTypeStatus_To_example3io_TestTypeStatus(in, out, s) +} + +func autoConvert_example3io_TestTypeStatus_To_v1_TestTypeStatus(in *example3io.TestTypeStatus, out *TestTypeStatus, s conversion.Scope) error { + out.Blah = in.Blah + return nil +} + +// Convert_example3io_TestTypeStatus_To_v1_TestTypeStatus is an autogenerated conversion function. +func Convert_example3io_TestTypeStatus_To_v1_TestTypeStatus(in *example3io.TestTypeStatus, out *TestTypeStatus, s conversion.Scope) error { + return autoConvert_example3io_TestTypeStatus_To_v1_TestTypeStatus(in, out, s) +} diff --git a/code-generator/examples/apiserver/apis/example3.io/v1/zz_generated.deepcopy.go b/code-generator/examples/apiserver/apis/example3.io/v1/zz_generated.deepcopy.go new file mode 100644 index 000000000..d87f706f7 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example3.io/v1/zz_generated.deepcopy.go @@ -0,0 +1,102 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/examples/apiserver/apis/example3.io/v1/zz_generated.defaults.go b/code-generator/examples/apiserver/apis/example3.io/v1/zz_generated.defaults.go new file mode 100644 index 000000000..dac177e93 --- /dev/null +++ b/code-generator/examples/apiserver/apis/example3.io/v1/zz_generated.defaults.go @@ -0,0 +1,33 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/code-generator/examples/apiserver/apis/example3.io/zz_generated.deepcopy.go b/code-generator/examples/apiserver/apis/example3.io/zz_generated.deepcopy.go new file mode 100644 index 000000000..2a976a9ee --- /dev/null +++ b/code-generator/examples/apiserver/apis/example3.io/zz_generated.deepcopy.go @@ -0,0 +1,102 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package example3 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/examples/apiserver/clientset/versioned/clientset.go b/code-generator/examples/apiserver/clientset/versioned/clientset.go new file mode 100644 index 000000000..347d4c27b --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/clientset.go @@ -0,0 +1,159 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package versioned + +import ( + fmt "fmt" + http "net/http" + + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" + corev1 "k8s.io/code-generator/examples/apiserver/clientset/versioned/typed/core/v1" + examplev1 "k8s.io/code-generator/examples/apiserver/clientset/versioned/typed/example/v1" + secondexamplev1 "k8s.io/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1" + thirdexamplev1 "k8s.io/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + CoreV1() corev1.CoreV1Interface + ExampleV1() examplev1.ExampleV1Interface + SecondExampleV1() secondexamplev1.SecondExampleV1Interface + ThirdExampleV1() thirdexamplev1.ThirdExampleV1Interface +} + +// Clientset contains the clients for groups. +type Clientset struct { + *discovery.DiscoveryClient + coreV1 *corev1.CoreV1Client + exampleV1 *examplev1.ExampleV1Client + secondExampleV1 *secondexamplev1.SecondExampleV1Client + thirdExampleV1 *thirdexamplev1.ThirdExampleV1Client +} + +// CoreV1 retrieves the CoreV1Client +func (c *Clientset) CoreV1() corev1.CoreV1Interface { + return c.coreV1 +} + +// ExampleV1 retrieves the ExampleV1Client +func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { + return c.exampleV1 +} + +// SecondExampleV1 retrieves the SecondExampleV1Client +func (c *Clientset) SecondExampleV1() secondexamplev1.SecondExampleV1Interface { + return c.secondExampleV1 +} + +// ThirdExampleV1 retrieves the ThirdExampleV1Client +func (c *Clientset) ThirdExampleV1() thirdexamplev1.ThirdExampleV1Interface { + return c.thirdExampleV1 +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfig will generate a rate-limiter in configShallowCopy. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + + if configShallowCopy.UserAgent == "" { + configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent() + } + + // share the transport between all clients + httpClient, err := rest.HTTPClientFor(&configShallowCopy) + if err != nil { + return nil, err + } + + return NewForConfigAndClient(&configShallowCopy, httpClient) +} + +// NewForConfigAndClient creates a new Clientset for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfigAndClient will generate a rate-limiter in configShallowCopy. +func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + if configShallowCopy.Burst <= 0 { + return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") + } + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + + var cs Clientset + var err error + cs.coreV1, err = corev1.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + cs.exampleV1, err = examplev1.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + cs.secondExampleV1, err = secondexamplev1.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + cs.thirdExampleV1, err = thirdexamplev1.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + cs, err := NewForConfig(c) + if err != nil { + panic(err) + } + return cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.coreV1 = corev1.New(c) + cs.exampleV1 = examplev1.New(c) + cs.secondExampleV1 = secondexamplev1.New(c) + cs.thirdExampleV1 = thirdexamplev1.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/code-generator/examples/apiserver/clientset/versioned/fake/clientset_generated.go b/code-generator/examples/apiserver/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 000000000..2e6319c46 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/fake/clientset_generated.go @@ -0,0 +1,110 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" + clientset "k8s.io/code-generator/examples/apiserver/clientset/versioned" + corev1 "k8s.io/code-generator/examples/apiserver/clientset/versioned/typed/core/v1" + fakecorev1 "k8s.io/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/fake" + examplev1 "k8s.io/code-generator/examples/apiserver/clientset/versioned/typed/example/v1" + fakeexamplev1 "k8s.io/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/fake" + secondexamplev1 "k8s.io/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1" + fakesecondexamplev1 "k8s.io/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/fake" + thirdexamplev1 "k8s.io/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1" + fakethirdexamplev1 "k8s.io/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/fake" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any field management, validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +// +// DEPRECATED: NewClientset replaces this with support for field management, which significantly improves +// server side apply testing. NewClientset is only available when apply configurations are generated (e.g. +// via --with-applyconfig). +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery + tracker testing.ObjectTracker +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +func (c *Clientset) Tracker() testing.ObjectTracker { + return c.tracker +} + +var ( + _ clientset.Interface = &Clientset{} + _ testing.FakeClient = &Clientset{} +) + +// CoreV1 retrieves the CoreV1Client +func (c *Clientset) CoreV1() corev1.CoreV1Interface { + return &fakecorev1.FakeCoreV1{Fake: &c.Fake} +} + +// ExampleV1 retrieves the ExampleV1Client +func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { + return &fakeexamplev1.FakeExampleV1{Fake: &c.Fake} +} + +// SecondExampleV1 retrieves the SecondExampleV1Client +func (c *Clientset) SecondExampleV1() secondexamplev1.SecondExampleV1Interface { + return &fakesecondexamplev1.FakeSecondExampleV1{Fake: &c.Fake} +} + +// ThirdExampleV1 retrieves the ThirdExampleV1Client +func (c *Clientset) ThirdExampleV1() thirdexamplev1.ThirdExampleV1Interface { + return &fakethirdexamplev1.FakeThirdExampleV1{Fake: &c.Fake} +} diff --git a/code-generator/examples/apiserver/clientset/versioned/fake/doc.go b/code-generator/examples/apiserver/clientset/versioned/fake/doc.go new file mode 100644 index 000000000..9b99e7167 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/code-generator/examples/apiserver/clientset/versioned/fake/register.go b/code-generator/examples/apiserver/clientset/versioned/fake/register.go new file mode 100644 index 000000000..c2a38a9fc --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/fake/register.go @@ -0,0 +1,62 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + corev1 "k8s.io/code-generator/examples/apiserver/apis/core/v1" + examplev1 "k8s.io/code-generator/examples/apiserver/apis/example/v1" + secondexamplev1 "k8s.io/code-generator/examples/apiserver/apis/example2/v1" + thirdexamplev1 "k8s.io/code-generator/examples/apiserver/apis/example3.io/v1" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) + +var localSchemeBuilder = runtime.SchemeBuilder{ + corev1.AddToScheme, + examplev1.AddToScheme, + secondexamplev1.AddToScheme, + thirdexamplev1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) +} diff --git a/code-generator/examples/apiserver/clientset/versioned/scheme/doc.go b/code-generator/examples/apiserver/clientset/versioned/scheme/doc.go new file mode 100644 index 000000000..7dc375616 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/scheme/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/code-generator/examples/apiserver/clientset/versioned/scheme/register.go b/code-generator/examples/apiserver/clientset/versioned/scheme/register.go new file mode 100644 index 000000000..1ea712906 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/scheme/register.go @@ -0,0 +1,62 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + corev1 "k8s.io/code-generator/examples/apiserver/apis/core/v1" + examplev1 "k8s.io/code-generator/examples/apiserver/apis/example/v1" + secondexamplev1 "k8s.io/code-generator/examples/apiserver/apis/example2/v1" + thirdexamplev1 "k8s.io/code-generator/examples/apiserver/apis/example3.io/v1" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + corev1.AddToScheme, + examplev1.AddToScheme, + secondexamplev1.AddToScheme, + thirdexamplev1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(Scheme)) +} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/core_client.go b/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/core_client.go new file mode 100644 index 000000000..32ff66818 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/core_client.go @@ -0,0 +1,107 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + http "net/http" + + rest "k8s.io/client-go/rest" + corev1 "k8s.io/code-generator/examples/apiserver/apis/core/v1" + scheme "k8s.io/code-generator/examples/apiserver/clientset/versioned/scheme" +) + +type CoreV1Interface interface { + RESTClient() rest.Interface + TestTypesGetter +} + +// CoreV1Client is used to interact with features provided by the group. +type CoreV1Client struct { + restClient rest.Interface +} + +func (c *CoreV1Client) TestTypes(namespace string) TestTypeInterface { + return newTestTypes(c, namespace) +} + +// NewForConfig creates a new CoreV1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*CoreV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new CoreV1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*CoreV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &CoreV1Client{client}, nil +} + +// NewForConfigOrDie creates a new CoreV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *CoreV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new CoreV1Client for the given RESTClient. +func New(c rest.Interface) *CoreV1Client { + return &CoreV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := corev1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/api" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *CoreV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/doc.go b/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/doc.go new file mode 100644 index 000000000..3af5d054f --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/fake/doc.go b/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/fake/fake_samplecontroller_client.go b/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/fake/fake_core_client.go similarity index 72% rename from pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/fake/fake_samplecontroller_client.go rename to code-generator/examples/apiserver/clientset/versioned/typed/core/v1/fake/fake_core_client.go index 02088eba8..2cdcda787 100644 --- a/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/fake/fake_samplecontroller_client.go +++ b/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/fake/fake_core_client.go @@ -21,20 +21,20 @@ package fake import ( rest "k8s.io/client-go/rest" testing "k8s.io/client-go/testing" - v1alpha1 "k8s.io/sample-controller/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1" + v1 "k8s.io/code-generator/examples/apiserver/clientset/versioned/typed/core/v1" ) -type FakeSamplecontrollerV1alpha1 struct { +type FakeCoreV1 struct { *testing.Fake } -func (c *FakeSamplecontrollerV1alpha1) Foos(namespace string) v1alpha1.FooInterface { - return &FakeFoos{c, namespace} +func (c *FakeCoreV1) TestTypes(namespace string) v1.TestTypeInterface { + return &FakeTestTypes{c, namespace} } // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. -func (c *FakeSamplecontrollerV1alpha1) RESTClient() rest.Interface { +func (c *FakeCoreV1) RESTClient() rest.Interface { var ret *rest.RESTClient return ret } diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/fake/fake_testtype.go b/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/fake/fake_testtype.go new file mode 100644 index 000000000..5dd2dca05 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/fake/fake_testtype.go @@ -0,0 +1,147 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/apiserver/apis/core/v1" +) + +// FakeTestTypes implements TestTypeInterface +type FakeTestTypes struct { + Fake *FakeCoreV1 + ns string +} + +var testtypesResource = v1.SchemeGroupVersion.WithResource("testtypes") + +var testtypesKind = v1.SchemeGroupVersion.WithKind("TestType") + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewGetActionWithOptions(testtypesResource, c.ns, name, options), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *FakeTestTypes) List(ctx context.Context, opts metav1.ListOptions) (result *v1.TestTypeList, err error) { + emptyResult := &v1.TestTypeList{} + obj, err := c.Fake. + Invokes(testing.NewListActionWithOptions(testtypesResource, testtypesKind, c.ns, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1.TestTypeList{ListMeta: obj.(*v1.TestTypeList).ListMeta} + for _, item := range obj.(*v1.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchActionWithOptions(testtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Create(ctx context.Context, testType *v1.TestType, opts metav1.CreateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewCreateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Update(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTestTypes) UpdateStatus(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceActionWithOptions(testtypesResource, "status", c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *FakeTestTypes) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(testtypesResource, c.ns, name, opts), &v1.TestType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTestTypes) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + action := testing.NewDeleteCollectionActionWithOptions(testtypesResource, c.ns, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1.TestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched testType. +func (c *FakeTestTypes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} diff --git a/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/generated_expansion.go b/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/generated_expansion.go similarity index 92% rename from pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/generated_expansion.go rename to code-generator/examples/apiserver/clientset/versioned/typed/core/v1/generated_expansion.go index b64ea0250..d513810d0 100644 --- a/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/generated_expansion.go +++ b/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/generated_expansion.go @@ -16,6 +16,6 @@ limitations under the License. // Code generated by client-gen. DO NOT EDIT. -package v1alpha1 +package v1 -type FooExpansion interface{} +type TestTypeExpansion interface{} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/testtype.go b/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/testtype.go new file mode 100644 index 000000000..69c862041 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/core/v1/testtype.go @@ -0,0 +1,69 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + corev1 "k8s.io/code-generator/examples/apiserver/apis/core/v1" + scheme "k8s.io/code-generator/examples/apiserver/clientset/versioned/scheme" +) + +// TestTypesGetter has a method to return a TestTypeInterface. +// A group's client should implement this interface. +type TestTypesGetter interface { + TestTypes(namespace string) TestTypeInterface +} + +// TestTypeInterface has methods to work with TestType resources. +type TestTypeInterface interface { + Create(ctx context.Context, testType *corev1.TestType, opts metav1.CreateOptions) (*corev1.TestType, error) + Update(ctx context.Context, testType *corev1.TestType, opts metav1.UpdateOptions) (*corev1.TestType, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, testType *corev1.TestType, opts metav1.UpdateOptions) (*corev1.TestType, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*corev1.TestType, error) + List(ctx context.Context, opts metav1.ListOptions) (*corev1.TestTypeList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *corev1.TestType, err error) + TestTypeExpansion +} + +// testTypes implements TestTypeInterface +type testTypes struct { + *gentype.ClientWithList[*corev1.TestType, *corev1.TestTypeList] +} + +// newTestTypes returns a TestTypes +func newTestTypes(c *CoreV1Client, namespace string) *testTypes { + return &testTypes{ + gentype.NewClientWithList[*corev1.TestType, *corev1.TestTypeList]( + "testtypes", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *corev1.TestType { return &corev1.TestType{} }, + func() *corev1.TestTypeList { return &corev1.TestTypeList{} }), + } +} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/doc.go b/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/doc.go new file mode 100644 index 000000000..3af5d054f --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/example_client.go b/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/example_client.go new file mode 100644 index 000000000..83bab2978 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/example_client.go @@ -0,0 +1,107 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + http "net/http" + + rest "k8s.io/client-go/rest" + examplev1 "k8s.io/code-generator/examples/apiserver/apis/example/v1" + scheme "k8s.io/code-generator/examples/apiserver/clientset/versioned/scheme" +) + +type ExampleV1Interface interface { + RESTClient() rest.Interface + TestTypesGetter +} + +// ExampleV1Client is used to interact with features provided by the example.apiserver.code-generator.k8s.io group. +type ExampleV1Client struct { + restClient rest.Interface +} + +func (c *ExampleV1Client) TestTypes(namespace string) TestTypeInterface { + return newTestTypes(c, namespace) +} + +// NewForConfig creates a new ExampleV1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*ExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new ExampleV1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*ExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &ExampleV1Client{client}, nil +} + +// NewForConfigOrDie creates a new ExampleV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ExampleV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ExampleV1Client for the given RESTClient. +func New(c rest.Interface) *ExampleV1Client { + return &ExampleV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := examplev1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *ExampleV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/fake/doc.go b/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_example_client.go b/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_example_client.go new file mode 100644 index 000000000..e13ab6a37 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_example_client.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/apiserver/clientset/versioned/typed/example/v1" +) + +type FakeExampleV1 struct { + *testing.Fake +} + +func (c *FakeExampleV1) TestTypes(namespace string) v1.TestTypeInterface { + return &FakeTestTypes{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeExampleV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_testtype.go b/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_testtype.go new file mode 100644 index 000000000..418372253 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/fake/fake_testtype.go @@ -0,0 +1,147 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/apiserver/apis/example/v1" +) + +// FakeTestTypes implements TestTypeInterface +type FakeTestTypes struct { + Fake *FakeExampleV1 + ns string +} + +var testtypesResource = v1.SchemeGroupVersion.WithResource("testtypes") + +var testtypesKind = v1.SchemeGroupVersion.WithKind("TestType") + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewGetActionWithOptions(testtypesResource, c.ns, name, options), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *FakeTestTypes) List(ctx context.Context, opts metav1.ListOptions) (result *v1.TestTypeList, err error) { + emptyResult := &v1.TestTypeList{} + obj, err := c.Fake. + Invokes(testing.NewListActionWithOptions(testtypesResource, testtypesKind, c.ns, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1.TestTypeList{ListMeta: obj.(*v1.TestTypeList).ListMeta} + for _, item := range obj.(*v1.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchActionWithOptions(testtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Create(ctx context.Context, testType *v1.TestType, opts metav1.CreateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewCreateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Update(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTestTypes) UpdateStatus(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceActionWithOptions(testtypesResource, "status", c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *FakeTestTypes) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(testtypesResource, c.ns, name, opts), &v1.TestType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTestTypes) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + action := testing.NewDeleteCollectionActionWithOptions(testtypesResource, c.ns, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1.TestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched testType. +func (c *FakeTestTypes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/generated_expansion.go b/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/generated_expansion.go new file mode 100644 index 000000000..d513810d0 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/generated_expansion.go @@ -0,0 +1,21 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type TestTypeExpansion interface{} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/testtype.go b/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/testtype.go new file mode 100644 index 000000000..4d7a5a001 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example/v1/testtype.go @@ -0,0 +1,69 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + examplev1 "k8s.io/code-generator/examples/apiserver/apis/example/v1" + scheme "k8s.io/code-generator/examples/apiserver/clientset/versioned/scheme" +) + +// TestTypesGetter has a method to return a TestTypeInterface. +// A group's client should implement this interface. +type TestTypesGetter interface { + TestTypes(namespace string) TestTypeInterface +} + +// TestTypeInterface has methods to work with TestType resources. +type TestTypeInterface interface { + Create(ctx context.Context, testType *examplev1.TestType, opts metav1.CreateOptions) (*examplev1.TestType, error) + Update(ctx context.Context, testType *examplev1.TestType, opts metav1.UpdateOptions) (*examplev1.TestType, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, testType *examplev1.TestType, opts metav1.UpdateOptions) (*examplev1.TestType, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*examplev1.TestType, error) + List(ctx context.Context, opts metav1.ListOptions) (*examplev1.TestTypeList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *examplev1.TestType, err error) + TestTypeExpansion +} + +// testTypes implements TestTypeInterface +type testTypes struct { + *gentype.ClientWithList[*examplev1.TestType, *examplev1.TestTypeList] +} + +// newTestTypes returns a TestTypes +func newTestTypes(c *ExampleV1Client, namespace string) *testTypes { + return &testTypes{ + gentype.NewClientWithList[*examplev1.TestType, *examplev1.TestTypeList]( + "testtypes", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *examplev1.TestType { return &examplev1.TestType{} }, + func() *examplev1.TestTypeList { return &examplev1.TestTypeList{} }), + } +} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/doc.go b/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/doc.go new file mode 100644 index 000000000..3af5d054f --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/example2_client.go b/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/example2_client.go new file mode 100644 index 000000000..50d3f57bc --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/example2_client.go @@ -0,0 +1,107 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + http "net/http" + + rest "k8s.io/client-go/rest" + example2v1 "k8s.io/code-generator/examples/apiserver/apis/example2/v1" + scheme "k8s.io/code-generator/examples/apiserver/clientset/versioned/scheme" +) + +type SecondExampleV1Interface interface { + RESTClient() rest.Interface + TestTypesGetter +} + +// SecondExampleV1Client is used to interact with features provided by the example.test.apiserver.code-generator.k8s.io group. +type SecondExampleV1Client struct { + restClient rest.Interface +} + +func (c *SecondExampleV1Client) TestTypes(namespace string) TestTypeInterface { + return newTestTypes(c, namespace) +} + +// NewForConfig creates a new SecondExampleV1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*SecondExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new SecondExampleV1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*SecondExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &SecondExampleV1Client{client}, nil +} + +// NewForConfigOrDie creates a new SecondExampleV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *SecondExampleV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new SecondExampleV1Client for the given RESTClient. +func New(c rest.Interface) *SecondExampleV1Client { + return &SecondExampleV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := example2v1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *SecondExampleV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/fake/doc.go b/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go b/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go new file mode 100644 index 000000000..6ac144fb3 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1" +) + +type FakeSecondExampleV1 struct { + *testing.Fake +} + +func (c *FakeSecondExampleV1) TestTypes(namespace string) v1.TestTypeInterface { + return &FakeTestTypes{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeSecondExampleV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_testtype.go b/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_testtype.go new file mode 100644 index 000000000..33b7ad5af --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/fake/fake_testtype.go @@ -0,0 +1,147 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/apiserver/apis/example2/v1" +) + +// FakeTestTypes implements TestTypeInterface +type FakeTestTypes struct { + Fake *FakeSecondExampleV1 + ns string +} + +var testtypesResource = v1.SchemeGroupVersion.WithResource("testtypes") + +var testtypesKind = v1.SchemeGroupVersion.WithKind("TestType") + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewGetActionWithOptions(testtypesResource, c.ns, name, options), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *FakeTestTypes) List(ctx context.Context, opts metav1.ListOptions) (result *v1.TestTypeList, err error) { + emptyResult := &v1.TestTypeList{} + obj, err := c.Fake. + Invokes(testing.NewListActionWithOptions(testtypesResource, testtypesKind, c.ns, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1.TestTypeList{ListMeta: obj.(*v1.TestTypeList).ListMeta} + for _, item := range obj.(*v1.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchActionWithOptions(testtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Create(ctx context.Context, testType *v1.TestType, opts metav1.CreateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewCreateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Update(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTestTypes) UpdateStatus(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceActionWithOptions(testtypesResource, "status", c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *FakeTestTypes) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(testtypesResource, c.ns, name, opts), &v1.TestType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTestTypes) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + action := testing.NewDeleteCollectionActionWithOptions(testtypesResource, c.ns, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1.TestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched testType. +func (c *FakeTestTypes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/generated_expansion.go b/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/generated_expansion.go new file mode 100644 index 000000000..d513810d0 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/generated_expansion.go @@ -0,0 +1,21 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type TestTypeExpansion interface{} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/testtype.go b/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/testtype.go new file mode 100644 index 000000000..06dcab4de --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example2/v1/testtype.go @@ -0,0 +1,69 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + example2v1 "k8s.io/code-generator/examples/apiserver/apis/example2/v1" + scheme "k8s.io/code-generator/examples/apiserver/clientset/versioned/scheme" +) + +// TestTypesGetter has a method to return a TestTypeInterface. +// A group's client should implement this interface. +type TestTypesGetter interface { + TestTypes(namespace string) TestTypeInterface +} + +// TestTypeInterface has methods to work with TestType resources. +type TestTypeInterface interface { + Create(ctx context.Context, testType *example2v1.TestType, opts metav1.CreateOptions) (*example2v1.TestType, error) + Update(ctx context.Context, testType *example2v1.TestType, opts metav1.UpdateOptions) (*example2v1.TestType, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, testType *example2v1.TestType, opts metav1.UpdateOptions) (*example2v1.TestType, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*example2v1.TestType, error) + List(ctx context.Context, opts metav1.ListOptions) (*example2v1.TestTypeList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *example2v1.TestType, err error) + TestTypeExpansion +} + +// testTypes implements TestTypeInterface +type testTypes struct { + *gentype.ClientWithList[*example2v1.TestType, *example2v1.TestTypeList] +} + +// newTestTypes returns a TestTypes +func newTestTypes(c *SecondExampleV1Client, namespace string) *testTypes { + return &testTypes{ + gentype.NewClientWithList[*example2v1.TestType, *example2v1.TestTypeList]( + "testtypes", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *example2v1.TestType { return &example2v1.TestType{} }, + func() *example2v1.TestTypeList { return &example2v1.TestTypeList{} }), + } +} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/doc.go b/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/doc.go new file mode 100644 index 000000000..3af5d054f --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/example3.io_client.go b/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/example3.io_client.go new file mode 100644 index 000000000..8d23b8771 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/example3.io_client.go @@ -0,0 +1,107 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + http "net/http" + + rest "k8s.io/client-go/rest" + example3iov1 "k8s.io/code-generator/examples/apiserver/apis/example3.io/v1" + scheme "k8s.io/code-generator/examples/apiserver/clientset/versioned/scheme" +) + +type ThirdExampleV1Interface interface { + RESTClient() rest.Interface + TestTypesGetter +} + +// ThirdExampleV1Client is used to interact with features provided by the example.dots.apiserver.code-generator.k8s.io group. +type ThirdExampleV1Client struct { + restClient rest.Interface +} + +func (c *ThirdExampleV1Client) TestTypes(namespace string) TestTypeInterface { + return newTestTypes(c, namespace) +} + +// NewForConfig creates a new ThirdExampleV1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*ThirdExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new ThirdExampleV1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*ThirdExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &ThirdExampleV1Client{client}, nil +} + +// NewForConfigOrDie creates a new ThirdExampleV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ThirdExampleV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ThirdExampleV1Client for the given RESTClient. +func New(c rest.Interface) *ThirdExampleV1Client { + return &ThirdExampleV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := example3iov1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *ThirdExampleV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/fake/doc.go b/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/fake/fake_example3.io_client.go b/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/fake/fake_example3.io_client.go new file mode 100644 index 000000000..265107442 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/fake/fake_example3.io_client.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1" +) + +type FakeThirdExampleV1 struct { + *testing.Fake +} + +func (c *FakeThirdExampleV1) TestTypes(namespace string) v1.TestTypeInterface { + return &FakeTestTypes{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeThirdExampleV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/fake/fake_testtype.go b/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/fake/fake_testtype.go new file mode 100644 index 000000000..1d1f530f9 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/fake/fake_testtype.go @@ -0,0 +1,147 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/apiserver/apis/example3.io/v1" +) + +// FakeTestTypes implements TestTypeInterface +type FakeTestTypes struct { + Fake *FakeThirdExampleV1 + ns string +} + +var testtypesResource = v1.SchemeGroupVersion.WithResource("testtypes") + +var testtypesKind = v1.SchemeGroupVersion.WithKind("TestType") + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewGetActionWithOptions(testtypesResource, c.ns, name, options), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *FakeTestTypes) List(ctx context.Context, opts metav1.ListOptions) (result *v1.TestTypeList, err error) { + emptyResult := &v1.TestTypeList{} + obj, err := c.Fake. + Invokes(testing.NewListActionWithOptions(testtypesResource, testtypesKind, c.ns, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1.TestTypeList{ListMeta: obj.(*v1.TestTypeList).ListMeta} + for _, item := range obj.(*v1.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchActionWithOptions(testtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Create(ctx context.Context, testType *v1.TestType, opts metav1.CreateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewCreateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Update(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTestTypes) UpdateStatus(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceActionWithOptions(testtypesResource, "status", c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *FakeTestTypes) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(testtypesResource, c.ns, name, opts), &v1.TestType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTestTypes) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + action := testing.NewDeleteCollectionActionWithOptions(testtypesResource, c.ns, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1.TestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched testType. +func (c *FakeTestTypes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/generated_expansion.go b/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/generated_expansion.go new file mode 100644 index 000000000..d513810d0 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/generated_expansion.go @@ -0,0 +1,21 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type TestTypeExpansion interface{} diff --git a/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/testtype.go b/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/testtype.go new file mode 100644 index 000000000..13e8a7975 --- /dev/null +++ b/code-generator/examples/apiserver/clientset/versioned/typed/example3.io/v1/testtype.go @@ -0,0 +1,69 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + example3iov1 "k8s.io/code-generator/examples/apiserver/apis/example3.io/v1" + scheme "k8s.io/code-generator/examples/apiserver/clientset/versioned/scheme" +) + +// TestTypesGetter has a method to return a TestTypeInterface. +// A group's client should implement this interface. +type TestTypesGetter interface { + TestTypes(namespace string) TestTypeInterface +} + +// TestTypeInterface has methods to work with TestType resources. +type TestTypeInterface interface { + Create(ctx context.Context, testType *example3iov1.TestType, opts metav1.CreateOptions) (*example3iov1.TestType, error) + Update(ctx context.Context, testType *example3iov1.TestType, opts metav1.UpdateOptions) (*example3iov1.TestType, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, testType *example3iov1.TestType, opts metav1.UpdateOptions) (*example3iov1.TestType, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*example3iov1.TestType, error) + List(ctx context.Context, opts metav1.ListOptions) (*example3iov1.TestTypeList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *example3iov1.TestType, err error) + TestTypeExpansion +} + +// testTypes implements TestTypeInterface +type testTypes struct { + *gentype.ClientWithList[*example3iov1.TestType, *example3iov1.TestTypeList] +} + +// newTestTypes returns a TestTypes +func newTestTypes(c *ThirdExampleV1Client, namespace string) *testTypes { + return &testTypes{ + gentype.NewClientWithList[*example3iov1.TestType, *example3iov1.TestTypeList]( + "testtypes", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *example3iov1.TestType { return &example3iov1.TestType{} }, + func() *example3iov1.TestTypeList { return &example3iov1.TestTypeList{} }), + } +} diff --git a/code-generator/examples/apiserver/informers/externalversions/core/interface.go b/code-generator/examples/apiserver/informers/externalversions/core/interface.go new file mode 100644 index 000000000..56a1bc41a --- /dev/null +++ b/code-generator/examples/apiserver/informers/externalversions/core/interface.go @@ -0,0 +1,46 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package core + +import ( + v1 "k8s.io/code-generator/examples/apiserver/informers/externalversions/core/v1" + internalinterfaces "k8s.io/code-generator/examples/apiserver/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/code-generator/examples/apiserver/informers/externalversions/core/v1/interface.go b/code-generator/examples/apiserver/informers/externalversions/core/v1/interface.go new file mode 100644 index 000000000..32180c91f --- /dev/null +++ b/code-generator/examples/apiserver/informers/externalversions/core/v1/interface.go @@ -0,0 +1,45 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "k8s.io/code-generator/examples/apiserver/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // TestTypes returns a TestTypeInformer. + TestTypes() TestTypeInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// TestTypes returns a TestTypeInformer. +func (v *version) TestTypes() TestTypeInformer { + return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/code-generator/examples/apiserver/informers/externalversions/core/v1/testtype.go b/code-generator/examples/apiserver/informers/externalversions/core/v1/testtype.go new file mode 100644 index 000000000..e98d1056b --- /dev/null +++ b/code-generator/examples/apiserver/informers/externalversions/core/v1/testtype.go @@ -0,0 +1,90 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + apiscorev1 "k8s.io/code-generator/examples/apiserver/apis/core/v1" + versioned "k8s.io/code-generator/examples/apiserver/clientset/versioned" + internalinterfaces "k8s.io/code-generator/examples/apiserver/informers/externalversions/internalinterfaces" + corev1 "k8s.io/code-generator/examples/apiserver/listers/core/v1" +) + +// TestTypeInformer provides access to a shared informer and lister for +// TestTypes. +type TestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() corev1.TestTypeLister +} + +type testTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.CoreV1().TestTypes(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.CoreV1().TestTypes(namespace).Watch(context.TODO(), options) + }, + }, + &apiscorev1.TestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *testTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apiscorev1.TestType{}, f.defaultInformer) +} + +func (f *testTypeInformer) Lister() corev1.TestTypeLister { + return corev1.NewTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/code-generator/examples/apiserver/informers/externalversions/example/interface.go b/code-generator/examples/apiserver/informers/externalversions/example/interface.go new file mode 100644 index 000000000..33dc89d5f --- /dev/null +++ b/code-generator/examples/apiserver/informers/externalversions/example/interface.go @@ -0,0 +1,46 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package example + +import ( + v1 "k8s.io/code-generator/examples/apiserver/informers/externalversions/example/v1" + internalinterfaces "k8s.io/code-generator/examples/apiserver/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/code-generator/examples/apiserver/informers/externalversions/example/v1/interface.go b/code-generator/examples/apiserver/informers/externalversions/example/v1/interface.go new file mode 100644 index 000000000..32180c91f --- /dev/null +++ b/code-generator/examples/apiserver/informers/externalversions/example/v1/interface.go @@ -0,0 +1,45 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "k8s.io/code-generator/examples/apiserver/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // TestTypes returns a TestTypeInformer. + TestTypes() TestTypeInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// TestTypes returns a TestTypeInformer. +func (v *version) TestTypes() TestTypeInformer { + return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/code-generator/examples/apiserver/informers/externalversions/example/v1/testtype.go b/code-generator/examples/apiserver/informers/externalversions/example/v1/testtype.go new file mode 100644 index 000000000..6ac2aab4f --- /dev/null +++ b/code-generator/examples/apiserver/informers/externalversions/example/v1/testtype.go @@ -0,0 +1,90 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + apisexamplev1 "k8s.io/code-generator/examples/apiserver/apis/example/v1" + versioned "k8s.io/code-generator/examples/apiserver/clientset/versioned" + internalinterfaces "k8s.io/code-generator/examples/apiserver/informers/externalversions/internalinterfaces" + examplev1 "k8s.io/code-generator/examples/apiserver/listers/example/v1" +) + +// TestTypeInformer provides access to a shared informer and lister for +// TestTypes. +type TestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() examplev1.TestTypeLister +} + +type testTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().TestTypes(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().TestTypes(namespace).Watch(context.TODO(), options) + }, + }, + &apisexamplev1.TestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *testTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apisexamplev1.TestType{}, f.defaultInformer) +} + +func (f *testTypeInformer) Lister() examplev1.TestTypeLister { + return examplev1.NewTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/code-generator/examples/apiserver/informers/externalversions/example2/interface.go b/code-generator/examples/apiserver/informers/externalversions/example2/interface.go new file mode 100644 index 000000000..4e68f0623 --- /dev/null +++ b/code-generator/examples/apiserver/informers/externalversions/example2/interface.go @@ -0,0 +1,46 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package example2 + +import ( + v1 "k8s.io/code-generator/examples/apiserver/informers/externalversions/example2/v1" + internalinterfaces "k8s.io/code-generator/examples/apiserver/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/code-generator/examples/apiserver/informers/externalversions/example2/v1/interface.go b/code-generator/examples/apiserver/informers/externalversions/example2/v1/interface.go new file mode 100644 index 000000000..32180c91f --- /dev/null +++ b/code-generator/examples/apiserver/informers/externalversions/example2/v1/interface.go @@ -0,0 +1,45 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "k8s.io/code-generator/examples/apiserver/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // TestTypes returns a TestTypeInformer. + TestTypes() TestTypeInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// TestTypes returns a TestTypeInformer. +func (v *version) TestTypes() TestTypeInformer { + return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/code-generator/examples/apiserver/informers/externalversions/example2/v1/testtype.go b/code-generator/examples/apiserver/informers/externalversions/example2/v1/testtype.go new file mode 100644 index 000000000..0aa483ac8 --- /dev/null +++ b/code-generator/examples/apiserver/informers/externalversions/example2/v1/testtype.go @@ -0,0 +1,90 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + apisexample2v1 "k8s.io/code-generator/examples/apiserver/apis/example2/v1" + versioned "k8s.io/code-generator/examples/apiserver/clientset/versioned" + internalinterfaces "k8s.io/code-generator/examples/apiserver/informers/externalversions/internalinterfaces" + example2v1 "k8s.io/code-generator/examples/apiserver/listers/example2/v1" +) + +// TestTypeInformer provides access to a shared informer and lister for +// TestTypes. +type TestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() example2v1.TestTypeLister +} + +type testTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.SecondExampleV1().TestTypes(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.SecondExampleV1().TestTypes(namespace).Watch(context.TODO(), options) + }, + }, + &apisexample2v1.TestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *testTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apisexample2v1.TestType{}, f.defaultInformer) +} + +func (f *testTypeInformer) Lister() example2v1.TestTypeLister { + return example2v1.NewTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/code-generator/examples/apiserver/informers/externalversions/example3.io/interface.go b/code-generator/examples/apiserver/informers/externalversions/example3.io/interface.go new file mode 100644 index 000000000..b00a58a80 --- /dev/null +++ b/code-generator/examples/apiserver/informers/externalversions/example3.io/interface.go @@ -0,0 +1,46 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package example3 + +import ( + v1 "k8s.io/code-generator/examples/apiserver/informers/externalversions/example3.io/v1" + internalinterfaces "k8s.io/code-generator/examples/apiserver/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/code-generator/examples/apiserver/informers/externalversions/example3.io/v1/interface.go b/code-generator/examples/apiserver/informers/externalversions/example3.io/v1/interface.go new file mode 100644 index 000000000..32180c91f --- /dev/null +++ b/code-generator/examples/apiserver/informers/externalversions/example3.io/v1/interface.go @@ -0,0 +1,45 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "k8s.io/code-generator/examples/apiserver/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // TestTypes returns a TestTypeInformer. + TestTypes() TestTypeInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// TestTypes returns a TestTypeInformer. +func (v *version) TestTypes() TestTypeInformer { + return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/code-generator/examples/apiserver/informers/externalversions/example3.io/v1/testtype.go b/code-generator/examples/apiserver/informers/externalversions/example3.io/v1/testtype.go new file mode 100644 index 000000000..c046986e7 --- /dev/null +++ b/code-generator/examples/apiserver/informers/externalversions/example3.io/v1/testtype.go @@ -0,0 +1,90 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + apisexample3iov1 "k8s.io/code-generator/examples/apiserver/apis/example3.io/v1" + versioned "k8s.io/code-generator/examples/apiserver/clientset/versioned" + internalinterfaces "k8s.io/code-generator/examples/apiserver/informers/externalversions/internalinterfaces" + example3iov1 "k8s.io/code-generator/examples/apiserver/listers/example3.io/v1" +) + +// TestTypeInformer provides access to a shared informer and lister for +// TestTypes. +type TestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() example3iov1.TestTypeLister +} + +type testTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ThirdExampleV1().TestTypes(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ThirdExampleV1().TestTypes(namespace).Watch(context.TODO(), options) + }, + }, + &apisexample3iov1.TestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *testTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apisexample3iov1.TestType{}, f.defaultInformer) +} + +func (f *testTypeInformer) Lister() example3iov1.TestTypeLister { + return example3iov1.NewTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/code-generator/examples/apiserver/informers/externalversions/factory.go b/code-generator/examples/apiserver/informers/externalversions/factory.go new file mode 100644 index 000000000..5efa771d5 --- /dev/null +++ b/code-generator/examples/apiserver/informers/externalversions/factory.go @@ -0,0 +1,280 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + versioned "k8s.io/code-generator/examples/apiserver/clientset/versioned" + core "k8s.io/code-generator/examples/apiserver/informers/externalversions/core" + example "k8s.io/code-generator/examples/apiserver/informers/externalversions/example" + example2 "k8s.io/code-generator/examples/apiserver/informers/externalversions/example2" + example3io "k8s.io/code-generator/examples/apiserver/informers/externalversions/example3.io" + internalinterfaces "k8s.io/code-generator/examples/apiserver/informers/externalversions/internalinterfaces" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + transform cache.TransformFunc + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool + // wg tracks how many goroutines were started. + wg sync.WaitGroup + // shuttingDown is true when Shutdown has been called. It may still be running + // because it needs to wait for goroutines. + shuttingDown bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// WithTransform sets a transform on all informers. +func WithTransform(transform cache.TransformFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.transform = transform + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + if f.shuttingDown { + return + } + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + f.wg.Add(1) + // We need a new variable in each loop iteration, + // otherwise the goroutine would use the loop variable + // and that keeps changing. + informer := informer + go func() { + defer f.wg.Done() + informer.Run(stopCh) + }() + f.startedInformers[informerType] = true + } + } +} + +func (f *sharedInformerFactory) Shutdown() { + f.lock.Lock() + f.shuttingDown = true + f.lock.Unlock() + + // Will return immediately if there is nothing to wait for. + f.wg.Wait() +} + +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + informer.SetTransform(f.transform) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +// +// It is typically used like this: +// +// ctx, cancel := context.Background() +// defer cancel() +// factory := NewSharedInformerFactory(client, resyncPeriod) +// defer factory.WaitForStop() // Returns immediately if nothing was started. +// genericInformer := factory.ForResource(resource) +// typedInformer := factory.SomeAPIGroup().V1().SomeType() +// factory.Start(ctx.Done()) // Start processing these informers. +// synced := factory.WaitForCacheSync(ctx.Done()) +// for v, ok := range synced { +// if !ok { +// fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v) +// return +// } +// } +// +// // Creating informers can also be created after Start, but then +// // Start must be called again: +// anotherGenericInformer := factory.ForResource(resource) +// factory.Start(ctx.Done()) +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + + // Start initializes all requested informers. They are handled in goroutines + // which run until the stop channel gets closed. + // Warning: Start does not block. When run in a go-routine, it will race with a later WaitForCacheSync. + Start(stopCh <-chan struct{}) + + // Shutdown marks a factory as shutting down. At that point no new + // informers can be started anymore and Start will return without + // doing anything. + // + // In addition, Shutdown blocks until all goroutines have terminated. For that + // to happen, the close channel(s) that they were started with must be closed, + // either before Shutdown gets called or while it is waiting. + // + // Shutdown may be called multiple times, even concurrently. All such calls will + // block until all goroutines have terminated. + Shutdown() + + // WaitForCacheSync blocks until all started informers' caches were synced + // or the stop channel gets closed. + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + // ForResource gives generic access to a shared informer of the matching type. + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + + // InformerFor returns the SharedIndexInformer for obj using an internal + // client. + InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer + + Core() core.Interface + Example() example.Interface + SecondExample() example2.Interface + ThirdExample() example3io.Interface +} + +func (f *sharedInformerFactory) Core() core.Interface { + return core.New(f, f.namespace, f.tweakListOptions) +} + +func (f *sharedInformerFactory) Example() example.Interface { + return example.New(f, f.namespace, f.tweakListOptions) +} + +func (f *sharedInformerFactory) SecondExample() example2.Interface { + return example2.New(f, f.namespace, f.tweakListOptions) +} + +func (f *sharedInformerFactory) ThirdExample() example3io.Interface { + return example3io.New(f, f.namespace, f.tweakListOptions) +} diff --git a/code-generator/examples/apiserver/informers/externalversions/generic.go b/code-generator/examples/apiserver/informers/externalversions/generic.go new file mode 100644 index 000000000..f1b766797 --- /dev/null +++ b/code-generator/examples/apiserver/informers/externalversions/generic.go @@ -0,0 +1,77 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + fmt "fmt" + + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + v1 "k8s.io/code-generator/examples/apiserver/apis/core/v1" + examplev1 "k8s.io/code-generator/examples/apiserver/apis/example/v1" + example2v1 "k8s.io/code-generator/examples/apiserver/apis/example2/v1" + example3iov1 "k8s.io/code-generator/examples/apiserver/apis/example3.io/v1" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=core, Version=v1 + case v1.SchemeGroupVersion.WithResource("testtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Core().V1().TestTypes().Informer()}, nil + + // Group=example.apiserver.code-generator.k8s.io, Version=v1 + case examplev1.SchemeGroupVersion.WithResource("testtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Example().V1().TestTypes().Informer()}, nil + + // Group=example.dots.apiserver.code-generator.k8s.io, Version=v1 + case example3iov1.SchemeGroupVersion.WithResource("testtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.ThirdExample().V1().TestTypes().Informer()}, nil + + // Group=example.test.apiserver.code-generator.k8s.io, Version=v1 + case example2v1.SchemeGroupVersion.WithResource("testtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.SecondExample().V1().TestTypes().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/code-generator/examples/apiserver/informers/externalversions/internalinterfaces/factory_interfaces.go b/code-generator/examples/apiserver/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 000000000..25586f80b --- /dev/null +++ b/code-generator/examples/apiserver/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" + versioned "k8s.io/code-generator/examples/apiserver/clientset/versioned" +) + +// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +// TweakListOptionsFunc is a function that transforms a v1.ListOptions. +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/code-generator/examples/apiserver/listers/core/v1/expansion_generated.go b/code-generator/examples/apiserver/listers/core/v1/expansion_generated.go new file mode 100644 index 000000000..0192e05f0 --- /dev/null +++ b/code-generator/examples/apiserver/listers/core/v1/expansion_generated.go @@ -0,0 +1,27 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// TestTypeListerExpansion allows custom methods to be added to +// TestTypeLister. +type TestTypeListerExpansion interface{} + +// TestTypeNamespaceListerExpansion allows custom methods to be added to +// TestTypeNamespaceLister. +type TestTypeNamespaceListerExpansion interface{} diff --git a/code-generator/examples/apiserver/listers/core/v1/testtype.go b/code-generator/examples/apiserver/listers/core/v1/testtype.go new file mode 100644 index 000000000..b620aecee --- /dev/null +++ b/code-generator/examples/apiserver/listers/core/v1/testtype.go @@ -0,0 +1,70 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" + corev1 "k8s.io/code-generator/examples/apiserver/apis/core/v1" +) + +// TestTypeLister helps list TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeLister interface { + // List lists all TestTypes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*corev1.TestType, err error) + // TestTypes returns an object that can list and get TestTypes. + TestTypes(namespace string) TestTypeNamespaceLister + TestTypeListerExpansion +} + +// testTypeLister implements the TestTypeLister interface. +type testTypeLister struct { + listers.ResourceIndexer[*corev1.TestType] +} + +// NewTestTypeLister returns a new TestTypeLister. +func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { + return &testTypeLister{listers.New[*corev1.TestType](indexer, corev1.Resource("testtype"))} +} + +// TestTypes returns an object that can list and get TestTypes. +func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { + return testTypeNamespaceLister{listers.NewNamespaced[*corev1.TestType](s.ResourceIndexer, namespace)} +} + +// TestTypeNamespaceLister helps list and get TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeNamespaceLister interface { + // List lists all TestTypes in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*corev1.TestType, err error) + // Get retrieves the TestType from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*corev1.TestType, error) + TestTypeNamespaceListerExpansion +} + +// testTypeNamespaceLister implements the TestTypeNamespaceLister +// interface. +type testTypeNamespaceLister struct { + listers.ResourceIndexer[*corev1.TestType] +} diff --git a/code-generator/examples/apiserver/listers/example/v1/expansion_generated.go b/code-generator/examples/apiserver/listers/example/v1/expansion_generated.go new file mode 100644 index 000000000..0192e05f0 --- /dev/null +++ b/code-generator/examples/apiserver/listers/example/v1/expansion_generated.go @@ -0,0 +1,27 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// TestTypeListerExpansion allows custom methods to be added to +// TestTypeLister. +type TestTypeListerExpansion interface{} + +// TestTypeNamespaceListerExpansion allows custom methods to be added to +// TestTypeNamespaceLister. +type TestTypeNamespaceListerExpansion interface{} diff --git a/code-generator/examples/apiserver/listers/example/v1/testtype.go b/code-generator/examples/apiserver/listers/example/v1/testtype.go new file mode 100644 index 000000000..caf84018c --- /dev/null +++ b/code-generator/examples/apiserver/listers/example/v1/testtype.go @@ -0,0 +1,70 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" + examplev1 "k8s.io/code-generator/examples/apiserver/apis/example/v1" +) + +// TestTypeLister helps list TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeLister interface { + // List lists all TestTypes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*examplev1.TestType, err error) + // TestTypes returns an object that can list and get TestTypes. + TestTypes(namespace string) TestTypeNamespaceLister + TestTypeListerExpansion +} + +// testTypeLister implements the TestTypeLister interface. +type testTypeLister struct { + listers.ResourceIndexer[*examplev1.TestType] +} + +// NewTestTypeLister returns a new TestTypeLister. +func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { + return &testTypeLister{listers.New[*examplev1.TestType](indexer, examplev1.Resource("testtype"))} +} + +// TestTypes returns an object that can list and get TestTypes. +func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { + return testTypeNamespaceLister{listers.NewNamespaced[*examplev1.TestType](s.ResourceIndexer, namespace)} +} + +// TestTypeNamespaceLister helps list and get TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeNamespaceLister interface { + // List lists all TestTypes in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*examplev1.TestType, err error) + // Get retrieves the TestType from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*examplev1.TestType, error) + TestTypeNamespaceListerExpansion +} + +// testTypeNamespaceLister implements the TestTypeNamespaceLister +// interface. +type testTypeNamespaceLister struct { + listers.ResourceIndexer[*examplev1.TestType] +} diff --git a/pkg/generated/listers/samplecontroller/v1alpha1/expansion_generated.go b/code-generator/examples/apiserver/listers/example2/v1/expansion_generated.go similarity index 69% rename from pkg/generated/listers/samplecontroller/v1alpha1/expansion_generated.go rename to code-generator/examples/apiserver/listers/example2/v1/expansion_generated.go index 9a34636b0..c43caf240 100644 --- a/pkg/generated/listers/samplecontroller/v1alpha1/expansion_generated.go +++ b/code-generator/examples/apiserver/listers/example2/v1/expansion_generated.go @@ -16,12 +16,4 @@ limitations under the License. // Code generated by lister-gen. DO NOT EDIT. -package v1alpha1 - -// FooListerExpansion allows custom methods to be added to -// FooLister. -type FooListerExpansion interface{} - -// FooNamespaceListerExpansion allows custom methods to be added to -// FooNamespaceLister. -type FooNamespaceListerExpansion interface{} +package v1 diff --git a/code-generator/examples/apiserver/listers/example2/v1/testtype.go b/code-generator/examples/apiserver/listers/example2/v1/testtype.go new file mode 100644 index 000000000..43ed3f695 --- /dev/null +++ b/code-generator/examples/apiserver/listers/example2/v1/testtype.go @@ -0,0 +1,70 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" + example2v1 "k8s.io/code-generator/examples/apiserver/apis/example2/v1" +) + +// TestTypeLister helps list TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeLister interface { + // List lists all TestTypes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*example2v1.TestType, err error) + // TestTypes returns an object that can list and get TestTypes. + TestTypes(namespace string) TestTypeNamespaceLister + TestTypeListerExpansion +} + +// testTypeLister implements the TestTypeLister interface. +type testTypeLister struct { + listers.ResourceIndexer[*example2v1.TestType] +} + +// NewTestTypeLister returns a new TestTypeLister. +func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { + return &testTypeLister{listers.New[*example2v1.TestType](indexer, example2v1.Resource("testtype"))} +} + +// TestTypes returns an object that can list and get TestTypes. +func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { + return testTypeNamespaceLister{listers.NewNamespaced[*example2v1.TestType](s.ResourceIndexer, namespace)} +} + +// TestTypeNamespaceLister helps list and get TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeNamespaceLister interface { + // List lists all TestTypes in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*example2v1.TestType, err error) + // Get retrieves the TestType from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*example2v1.TestType, error) + TestTypeNamespaceListerExpansion +} + +// testTypeNamespaceLister implements the TestTypeNamespaceLister +// interface. +type testTypeNamespaceLister struct { + listers.ResourceIndexer[*example2v1.TestType] +} diff --git a/code-generator/examples/apiserver/listers/example2/v1/testtype_expansion.go b/code-generator/examples/apiserver/listers/example2/v1/testtype_expansion.go new file mode 100644 index 000000000..c135d2844 --- /dev/null +++ b/code-generator/examples/apiserver/listers/example2/v1/testtype_expansion.go @@ -0,0 +1,31 @@ +/* +Copyright 2024 The Kubernetes 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 v1 + +// TestTypeListerExpansion allows custom methods to be added to +// TestTypeLister. +type TestTypeListerExpansion interface { + CheckExpansionSupport() +} + +// TestTypeNamespaceListerExpansion allows custom methods to be added to +// TestTypeNamespaceLister. +type TestTypeNamespaceListerExpansion interface{} + +func (*testTypeLister) CheckExpansionSupport() { + // This checks that lister-gen correctly supports expansions +} diff --git a/code-generator/examples/apiserver/listers/example3.io/v1/expansion_generated.go b/code-generator/examples/apiserver/listers/example3.io/v1/expansion_generated.go new file mode 100644 index 000000000..0192e05f0 --- /dev/null +++ b/code-generator/examples/apiserver/listers/example3.io/v1/expansion_generated.go @@ -0,0 +1,27 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// TestTypeListerExpansion allows custom methods to be added to +// TestTypeLister. +type TestTypeListerExpansion interface{} + +// TestTypeNamespaceListerExpansion allows custom methods to be added to +// TestTypeNamespaceLister. +type TestTypeNamespaceListerExpansion interface{} diff --git a/code-generator/examples/apiserver/listers/example3.io/v1/testtype.go b/code-generator/examples/apiserver/listers/example3.io/v1/testtype.go new file mode 100644 index 000000000..96b2088ba --- /dev/null +++ b/code-generator/examples/apiserver/listers/example3.io/v1/testtype.go @@ -0,0 +1,70 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" + example3iov1 "k8s.io/code-generator/examples/apiserver/apis/example3.io/v1" +) + +// TestTypeLister helps list TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeLister interface { + // List lists all TestTypes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*example3iov1.TestType, err error) + // TestTypes returns an object that can list and get TestTypes. + TestTypes(namespace string) TestTypeNamespaceLister + TestTypeListerExpansion +} + +// testTypeLister implements the TestTypeLister interface. +type testTypeLister struct { + listers.ResourceIndexer[*example3iov1.TestType] +} + +// NewTestTypeLister returns a new TestTypeLister. +func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { + return &testTypeLister{listers.New[*example3iov1.TestType](indexer, example3iov1.Resource("testtype"))} +} + +// TestTypes returns an object that can list and get TestTypes. +func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { + return testTypeNamespaceLister{listers.NewNamespaced[*example3iov1.TestType](s.ResourceIndexer, namespace)} +} + +// TestTypeNamespaceLister helps list and get TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeNamespaceLister interface { + // List lists all TestTypes in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*example3iov1.TestType, err error) + // Get retrieves the TestType from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*example3iov1.TestType, error) + TestTypeNamespaceListerExpansion +} + +// testTypeNamespaceLister implements the TestTypeNamespaceLister +// interface. +type testTypeNamespaceLister struct { + listers.ResourceIndexer[*example3iov1.TestType] +} diff --git a/code-generator/examples/apiserver/openapi/zz_generated.openapi.go b/code-generator/examples/apiserver/openapi/zz_generated.openapi.go new file mode 100644 index 000000000..2c1d8713b --- /dev/null +++ b/code-generator/examples/apiserver/openapi/zz_generated.openapi.go @@ -0,0 +1,3127 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by openapi-gen. DO NOT EDIT. + +package openapi + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + common "k8s.io/kube-openapi/pkg/common" + spec "k8s.io/kube-openapi/pkg/validation/spec" +) + +func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenAPIDefinition { + return map[string]common.OpenAPIDefinition{ + "k8s.io/apimachinery/pkg/apis/meta/v1.APIGroup": schema_pkg_apis_meta_v1_APIGroup(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.APIGroupList": schema_pkg_apis_meta_v1_APIGroupList(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.APIResource": schema_pkg_apis_meta_v1_APIResource(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.APIResourceList": schema_pkg_apis_meta_v1_APIResourceList(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.APIVersions": schema_pkg_apis_meta_v1_APIVersions(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.ApplyOptions": schema_pkg_apis_meta_v1_ApplyOptions(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.Condition": schema_pkg_apis_meta_v1_Condition(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.CreateOptions": schema_pkg_apis_meta_v1_CreateOptions(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.DeleteOptions": schema_pkg_apis_meta_v1_DeleteOptions(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.Duration": schema_pkg_apis_meta_v1_Duration(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.FieldSelectorRequirement": schema_pkg_apis_meta_v1_FieldSelectorRequirement(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.FieldsV1": schema_pkg_apis_meta_v1_FieldsV1(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.GetOptions": schema_pkg_apis_meta_v1_GetOptions(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.GroupKind": schema_pkg_apis_meta_v1_GroupKind(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.GroupResource": schema_pkg_apis_meta_v1_GroupResource(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersion": schema_pkg_apis_meta_v1_GroupVersion(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionForDiscovery": schema_pkg_apis_meta_v1_GroupVersionForDiscovery(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionKind": schema_pkg_apis_meta_v1_GroupVersionKind(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionResource": schema_pkg_apis_meta_v1_GroupVersionResource(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.InternalEvent": schema_pkg_apis_meta_v1_InternalEvent(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelector": schema_pkg_apis_meta_v1_LabelSelector(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelectorRequirement": schema_pkg_apis_meta_v1_LabelSelectorRequirement(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.List": schema_pkg_apis_meta_v1_List(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta": schema_pkg_apis_meta_v1_ListMeta(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.ListOptions": schema_pkg_apis_meta_v1_ListOptions(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.ManagedFieldsEntry": schema_pkg_apis_meta_v1_ManagedFieldsEntry(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.MicroTime": schema_pkg_apis_meta_v1_MicroTime(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta": schema_pkg_apis_meta_v1_ObjectMeta(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.OwnerReference": schema_pkg_apis_meta_v1_OwnerReference(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.PartialObjectMetadata": schema_pkg_apis_meta_v1_PartialObjectMetadata(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.PartialObjectMetadataList": schema_pkg_apis_meta_v1_PartialObjectMetadataList(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.Patch": schema_pkg_apis_meta_v1_Patch(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.PatchOptions": schema_pkg_apis_meta_v1_PatchOptions(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.Preconditions": schema_pkg_apis_meta_v1_Preconditions(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.RootPaths": schema_pkg_apis_meta_v1_RootPaths(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.ServerAddressByClientCIDR": schema_pkg_apis_meta_v1_ServerAddressByClientCIDR(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.Status": schema_pkg_apis_meta_v1_Status(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.StatusCause": schema_pkg_apis_meta_v1_StatusCause(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.StatusDetails": schema_pkg_apis_meta_v1_StatusDetails(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.Table": schema_pkg_apis_meta_v1_Table(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.TableColumnDefinition": schema_pkg_apis_meta_v1_TableColumnDefinition(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.TableOptions": schema_pkg_apis_meta_v1_TableOptions(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.TableRow": schema_pkg_apis_meta_v1_TableRow(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.TableRowCondition": schema_pkg_apis_meta_v1_TableRowCondition(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.Time": schema_pkg_apis_meta_v1_Time(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.Timestamp": schema_pkg_apis_meta_v1_Timestamp(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.TypeMeta": schema_pkg_apis_meta_v1_TypeMeta(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.UpdateOptions": schema_pkg_apis_meta_v1_UpdateOptions(ref), + "k8s.io/apimachinery/pkg/apis/meta/v1.WatchEvent": schema_pkg_apis_meta_v1_WatchEvent(ref), + "k8s.io/apimachinery/pkg/runtime.RawExtension": schema_k8sio_apimachinery_pkg_runtime_RawExtension(ref), + "k8s.io/apimachinery/pkg/runtime.TypeMeta": schema_k8sio_apimachinery_pkg_runtime_TypeMeta(ref), + "k8s.io/apimachinery/pkg/runtime.Unknown": schema_k8sio_apimachinery_pkg_runtime_Unknown(ref), + "k8s.io/apimachinery/pkg/version.Info": schema_k8sio_apimachinery_pkg_version_Info(ref), + "k8s.io/code-generator/examples/apiserver/apis/core/v1.TestType": schema_apiserver_apis_core_v1_TestType(ref), + "k8s.io/code-generator/examples/apiserver/apis/core/v1.TestTypeList": schema_apiserver_apis_core_v1_TestTypeList(ref), + "k8s.io/code-generator/examples/apiserver/apis/core/v1.TestTypeStatus": schema_apiserver_apis_core_v1_TestTypeStatus(ref), + "k8s.io/code-generator/examples/apiserver/apis/example/v1.TestType": schema_apiserver_apis_example_v1_TestType(ref), + "k8s.io/code-generator/examples/apiserver/apis/example/v1.TestTypeList": schema_apiserver_apis_example_v1_TestTypeList(ref), + "k8s.io/code-generator/examples/apiserver/apis/example/v1.TestTypeStatus": schema_apiserver_apis_example_v1_TestTypeStatus(ref), + "k8s.io/code-generator/examples/apiserver/apis/example2/v1.TestType": schema_apiserver_apis_example2_v1_TestType(ref), + "k8s.io/code-generator/examples/apiserver/apis/example2/v1.TestTypeList": schema_apiserver_apis_example2_v1_TestTypeList(ref), + "k8s.io/code-generator/examples/apiserver/apis/example2/v1.TestTypeStatus": schema_apiserver_apis_example2_v1_TestTypeStatus(ref), + "k8s.io/code-generator/examples/apiserver/apis/example3.io/v1.TestType": schema_apiserver_apis_example3io_v1_TestType(ref), + "k8s.io/code-generator/examples/apiserver/apis/example3.io/v1.TestTypeList": schema_apiserver_apis_example3io_v1_TestTypeList(ref), + "k8s.io/code-generator/examples/apiserver/apis/example3.io/v1.TestTypeStatus": schema_apiserver_apis_example3io_v1_TestTypeStatus(ref), + } +} + +func schema_pkg_apis_meta_v1_APIGroup(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "APIGroup contains the name, the supported versions, and the preferred version of a group.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is the name of the group.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "versions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "versions are the versions supported in this group.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionForDiscovery"), + }, + }, + }, + }, + }, + "preferredVersion": { + SchemaProps: spec.SchemaProps{ + Description: "preferredVersion is the version preferred by the API server, which probably is the storage version.", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionForDiscovery"), + }, + }, + "serverAddressByClientCIDRs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "a map of client CIDR to server address that is serving this group. This is to help clients reach servers in the most network-efficient way possible. Clients can use the appropriate server address as per the CIDR that they match. In case of multiple matches, clients should use the longest matching CIDR. The server returns only those CIDRs that it thinks that the client can match. For example: the master will return an internal IP CIDR only, if the client reaches the server using an internal IP. Server looks at X-Forwarded-For header or X-Real-Ip header or request.RemoteAddr (in that order) to get the client IP.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ServerAddressByClientCIDR"), + }, + }, + }, + }, + }, + }, + Required: []string{"name", "versions"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.GroupVersionForDiscovery", "k8s.io/apimachinery/pkg/apis/meta/v1.ServerAddressByClientCIDR"}, + } +} + +func schema_pkg_apis_meta_v1_APIGroupList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "APIGroupList is a list of APIGroup, to allow clients to discover the API at /apis.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "groups": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "groups is a list of APIGroup.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.APIGroup"), + }, + }, + }, + }, + }, + }, + Required: []string{"groups"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.APIGroup"}, + } +} + +func schema_pkg_apis_meta_v1_APIResource(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "APIResource specifies the name of a resource and whether it is namespaced.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is the plural name of the resource.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "singularName": { + SchemaProps: spec.SchemaProps{ + Description: "singularName is the singular name of the resource. This allows clients to handle plural and singular opaquely. The singularName is more correct for reporting status on a single item and both singular and plural are allowed from the kubectl CLI interface.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "namespaced": { + SchemaProps: spec.SchemaProps{ + Description: "namespaced indicates if a resource is namespaced or not.", + Default: false, + Type: []string{"boolean"}, + Format: "", + }, + }, + "group": { + SchemaProps: spec.SchemaProps{ + Description: "group is the preferred group of the resource. Empty implies the group of the containing resource list. For subresources, this may have a different value, for example: Scale\".", + Type: []string{"string"}, + Format: "", + }, + }, + "version": { + SchemaProps: spec.SchemaProps{ + Description: "version is the preferred version of the resource. Empty implies the version of the containing resource list For subresources, this may have a different value, for example: v1 (while inside a v1beta1 version of the core resource's group)\".", + Type: []string{"string"}, + Format: "", + }, + }, + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "kind is the kind for the resource (e.g. 'Foo' is the kind for a resource 'foo')", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "verbs": { + SchemaProps: spec.SchemaProps{ + Description: "verbs is a list of supported kube verbs (this includes get, list, watch, create, update, patch, delete, deletecollection, and proxy)", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "shortNames": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "shortNames is a list of suggested short names of the resource.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "categories": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "categories is a list of the grouped resources this resource belongs to (e.g. 'all')", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "storageVersionHash": { + SchemaProps: spec.SchemaProps{ + Description: "The hash value of the storage version, the version this resource is converted to when written to the data store. Value must be treated as opaque by clients. Only equality comparison on the value is valid. This is an alpha feature and may change or be removed in the future. The field is populated by the apiserver only if the StorageVersionHash feature gate is enabled. This field will remain optional even if it graduates.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"name", "singularName", "namespaced", "kind", "verbs"}, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_APIResourceList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "APIResourceList is a list of APIResource, it is used to expose the name of the resources supported in a specific group and version, and if the resource is namespaced.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "groupVersion": { + SchemaProps: spec.SchemaProps{ + Description: "groupVersion is the group and version this APIResourceList is for.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "resources": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "resources contains the name of the resources and if they are namespaced.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.APIResource"), + }, + }, + }, + }, + }, + }, + Required: []string{"groupVersion", "resources"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.APIResource"}, + } +} + +func schema_pkg_apis_meta_v1_APIVersions(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "APIVersions lists the versions that are available, to allow clients to discover the API at /api, which is the root path of the legacy v1 API.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "versions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "versions are the api versions that are available.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "serverAddressByClientCIDRs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "a map of client CIDR to server address that is serving this group. This is to help clients reach servers in the most network-efficient way possible. Clients can use the appropriate server address as per the CIDR that they match. In case of multiple matches, clients should use the longest matching CIDR. The server returns only those CIDRs that it thinks that the client can match. For example: the master will return an internal IP CIDR only, if the client reaches the server using an internal IP. Server looks at X-Forwarded-For header or X-Real-Ip header or request.RemoteAddr (in that order) to get the client IP.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ServerAddressByClientCIDR"), + }, + }, + }, + }, + }, + }, + Required: []string{"versions", "serverAddressByClientCIDRs"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ServerAddressByClientCIDR"}, + } +} + +func schema_pkg_apis_meta_v1_ApplyOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ApplyOptions may be provided when applying an API object. FieldManager is required for apply requests. ApplyOptions is equivalent to PatchOptions. It is provided as a convenience with documentation that speaks specifically to how the options fields relate to apply.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "dryRun": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "force": { + SchemaProps: spec.SchemaProps{ + Description: "Force is going to \"force\" Apply requests. It means user will re-acquire conflicting fields owned by other people.", + Default: false, + Type: []string{"boolean"}, + Format: "", + }, + }, + "fieldManager": { + SchemaProps: spec.SchemaProps{ + Description: "fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"force", "fieldManager"}, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_Condition(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Condition contains details for one aspect of the current state of this API Resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "type": { + SchemaProps: spec.SchemaProps{ + Description: "type of condition in CamelCase or in foo.example.com/CamelCase.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "status of the condition, one of True, False, Unknown.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "observedGeneration": { + SchemaProps: spec.SchemaProps{ + Description: "observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "lastTransitionTime": { + SchemaProps: spec.SchemaProps{ + Description: "lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "reason": { + SchemaProps: spec.SchemaProps{ + Description: "reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "message": { + SchemaProps: spec.SchemaProps{ + Description: "message is a human readable message indicating details about the transition. This may be an empty string.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"type", "status", "lastTransitionTime", "reason", "message"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_pkg_apis_meta_v1_CreateOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "CreateOptions may be provided when creating an API object.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "dryRun": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "fieldManager": { + SchemaProps: spec.SchemaProps{ + Description: "fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.", + Type: []string{"string"}, + Format: "", + }, + }, + "fieldValidation": { + SchemaProps: spec.SchemaProps{ + Description: "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_DeleteOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "DeleteOptions may be provided when deleting an API object.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "gracePeriodSeconds": { + SchemaProps: spec.SchemaProps{ + Description: "The duration in seconds before the object should be deleted. Value must be non-negative integer. The value zero indicates delete immediately. If this value is nil, the default grace period for the specified type will be used. Defaults to a per object value if not specified. zero means delete immediately.", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "preconditions": { + SchemaProps: spec.SchemaProps{ + Description: "Must be fulfilled before a deletion is carried out. If not possible, a 409 Conflict status will be returned.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Preconditions"), + }, + }, + "orphanDependents": { + SchemaProps: spec.SchemaProps{ + Description: "Deprecated: please use the PropagationPolicy, this field will be deprecated in 1.7. Should the dependent objects be orphaned. If true/false, the \"orphan\" finalizer will be added to/removed from the object's finalizers list. Either this field or PropagationPolicy may be set, but not both.", + Type: []string{"boolean"}, + Format: "", + }, + }, + "propagationPolicy": { + SchemaProps: spec.SchemaProps{ + Description: "Whether and how garbage collection will be performed. Either this field or OrphanDependents may be set, but not both. The default policy is decided by the existing finalizer set in the metadata.finalizers and the resource-specific default policy. Acceptable values are: 'Orphan' - orphan the dependents; 'Background' - allow the garbage collector to delete the dependents in the background; 'Foreground' - a cascading policy that deletes all dependents in the foreground.", + Type: []string{"string"}, + Format: "", + }, + }, + "dryRun": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.Preconditions"}, + } +} + +func schema_pkg_apis_meta_v1_Duration(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Duration is a wrapper around time.Duration which supports correct marshaling to YAML and JSON. In particular, it marshals into strings, which can be used as map keys in json.", + Type: v1.Duration{}.OpenAPISchemaType(), + Format: v1.Duration{}.OpenAPISchemaFormat(), + }, + }, + } +} + +func schema_pkg_apis_meta_v1_FieldSelectorRequirement(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FieldSelectorRequirement is a selector that contains values, a key, and an operator that relates the key and values.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "key": { + SchemaProps: spec.SchemaProps{ + Description: "key is the field selector key that the requirement applies to.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "operator": { + SchemaProps: spec.SchemaProps{ + Description: "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists, DoesNotExist. The list of operators may grow in the future.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "values": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + Required: []string{"key", "operator"}, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_FieldsV1(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FieldsV1 stores a set of fields in a data structure like a Trie, in JSON format.\n\nEach key is either a '.' representing the field itself, and will always map to an empty set, or a string representing a sub-field or item. The string will follow one of these four formats: 'f:', where is the name of a field in a struct, or key in a map 'v:', where is the exact json formatted value of a list item 'i:', where is position of a item in a list 'k:', where is a map of a list item's key fields to their unique values If a key maps to an empty Fields value, the field that key represents is part of the set.\n\nThe exact format is defined in sigs.k8s.io/structured-merge-diff", + Type: []string{"object"}, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_GetOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "GetOptions is the standard query options to the standard REST get call.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "resourceVersion": { + SchemaProps: spec.SchemaProps{ + Description: "resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details.\n\nDefaults to unset", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_GroupKind(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "GroupKind specifies a Group and a Kind, but does not force a version. This is useful for identifying concepts during lookup stages without having partially valid types", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "group": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "kind": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"group", "kind"}, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_GroupResource(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "GroupResource specifies a Group and a Resource, but does not force a version. This is useful for identifying concepts during lookup stages without having partially valid types", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "group": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"group", "resource"}, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_GroupVersion(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "GroupVersion contains the \"group\" and the \"version\", which uniquely identifies the API.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "group": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "version": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"group", "version"}, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_GroupVersionForDiscovery(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "GroupVersion contains the \"group/version\" and \"version\" string of a version. It is made a struct to keep extensibility.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "groupVersion": { + SchemaProps: spec.SchemaProps{ + Description: "groupVersion specifies the API group and version in the form \"group/version\"", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "version": { + SchemaProps: spec.SchemaProps{ + Description: "version specifies the version in the form of \"version\". This is to save the clients the trouble of splitting the GroupVersion.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"groupVersion", "version"}, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_GroupVersionKind(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "GroupVersionKind unambiguously identifies a kind. It doesn't anonymously include GroupVersion to avoid automatic coercion. It doesn't use a GroupVersion to avoid custom marshalling", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "group": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "version": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "kind": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"group", "version", "kind"}, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_GroupVersionResource(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "GroupVersionResource unambiguously identifies a resource. It doesn't anonymously include GroupVersion to avoid automatic coercion. It doesn't use a GroupVersion to avoid custom marshalling", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "group": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "version": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "resource": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"group", "version", "resource"}, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_InternalEvent(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "InternalEvent makes watch.Event versioned", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "Type": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "Object": { + SchemaProps: spec.SchemaProps{ + Description: "Object is:\n * If Type is Added or Modified: the new state of the object.\n * If Type is Deleted: the state of the object immediately before deletion.\n * If Type is Bookmark: the object (instance of a type being watched) where\n only ResourceVersion field is set. On successful restart of watch from a\n bookmark resourceVersion, client is guaranteed to not get repeat event\n nor miss any events.\n * If Type is Error: *api.Status is recommended; other types may make sense\n depending on context.", + Ref: ref("k8s.io/apimachinery/pkg/runtime.Object"), + }, + }, + }, + Required: []string{"Type", "Object"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/runtime.Object"}, + } +} + +func schema_pkg_apis_meta_v1_LabelSelector(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "A label selector is a label query over a set of resources. The result of matchLabels and matchExpressions are ANDed. An empty label selector matches all objects. A null label selector matches no objects.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "matchLabels": { + SchemaProps: spec.SchemaProps{ + Description: "matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is \"key\", the operator is \"In\", and the values array contains only \"value\". The requirements are ANDed.", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "matchExpressions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "matchExpressions is a list of label selector requirements. The requirements are ANDed.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelectorRequirement"), + }, + }, + }, + }, + }, + }, + }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.LabelSelectorRequirement"}, + } +} + +func schema_pkg_apis_meta_v1_LabelSelectorRequirement(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "key": { + SchemaProps: spec.SchemaProps{ + Description: "key is the label key that the selector applies to.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "operator": { + SchemaProps: spec.SchemaProps{ + Description: "operator represents a key's relationship to a set of values. Valid operators are In, NotIn, Exists and DoesNotExist.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "values": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "values is an array of string values. If the operator is In or NotIn, the values array must be non-empty. If the operator is Exists or DoesNotExist, the values array must be empty. This array is replaced during a strategic merge patch.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + Required: []string{"key", "operator"}, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_List(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "List holds a list of objects, which may not be known by the server.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "List of objects", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Ref: ref("k8s.io/apimachinery/pkg/runtime.RawExtension"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "k8s.io/apimachinery/pkg/runtime.RawExtension"}, + } +} + +func schema_pkg_apis_meta_v1_ListMeta(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ListMeta describes metadata that synthetic resources must have, including lists and various status objects. A resource may have only one of {ObjectMeta, ListMeta}.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "selfLink": { + SchemaProps: spec.SchemaProps{ + Description: "Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.", + Type: []string{"string"}, + Format: "", + }, + }, + "resourceVersion": { + SchemaProps: spec.SchemaProps{ + Description: "String that identifies the server's internal version of this object that can be used by clients to determine when objects have changed. Value must be treated as opaque by clients and passed unmodified back to the server. Populated by the system. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency", + Type: []string{"string"}, + Format: "", + }, + }, + "continue": { + SchemaProps: spec.SchemaProps{ + Description: "continue may be set if the user set a limit on the number of items returned, and indicates that the server has more data available. The value is opaque and may be used to issue another request to the endpoint that served this list to retrieve the next set of available objects. Continuing a consistent list may not be possible if the server configuration has changed or more than a few minutes have passed. The resourceVersion field returned when using this continue value will be identical to the value in the first response, unless you have received this token from an error message.", + Type: []string{"string"}, + Format: "", + }, + }, + "remainingItemCount": { + SchemaProps: spec.SchemaProps{ + Description: "remainingItemCount is the number of subsequent items in the list which are not included in this list response. If the list request contained label or field selectors, then the number of remaining items is unknown and the field will be left unset and omitted during serialization. If the list is complete (either because it is not chunking or because this is the last chunk), then there are no more remaining items and this field will be left unset and omitted during serialization. Servers older than v1.15 do not set this field. The intended use of the remainingItemCount is *estimating* the size of a collection. Clients should not rely on the remainingItemCount to be set or to be exact.", + Type: []string{"integer"}, + Format: "int64", + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_ListOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ListOptions is the query options to a standard REST list call.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "labelSelector": { + SchemaProps: spec.SchemaProps{ + Description: "A selector to restrict the list of returned objects by their labels. Defaults to everything.", + Type: []string{"string"}, + Format: "", + }, + }, + "fieldSelector": { + SchemaProps: spec.SchemaProps{ + Description: "A selector to restrict the list of returned objects by their fields. Defaults to everything.", + Type: []string{"string"}, + Format: "", + }, + }, + "watch": { + SchemaProps: spec.SchemaProps{ + Description: "Watch for changes to the described resources and return them as a stream of add, update, and remove notifications. Specify resourceVersion.", + Type: []string{"boolean"}, + Format: "", + }, + }, + "allowWatchBookmarks": { + SchemaProps: spec.SchemaProps{ + Description: "allowWatchBookmarks requests watch events with type \"BOOKMARK\". Servers that do not implement bookmarks may ignore this flag and bookmarks are sent at the server's discretion. Clients should not assume bookmarks are returned at any specific interval, nor may they assume the server will send any BOOKMARK event during a session. If this is not a watch, this field is ignored.", + Type: []string{"boolean"}, + Format: "", + }, + }, + "resourceVersion": { + SchemaProps: spec.SchemaProps{ + Description: "resourceVersion sets a constraint on what resource versions a request may be served from. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details.\n\nDefaults to unset", + Type: []string{"string"}, + Format: "", + }, + }, + "resourceVersionMatch": { + SchemaProps: spec.SchemaProps{ + Description: "resourceVersionMatch determines how resourceVersion is applied to list calls. It is highly recommended that resourceVersionMatch be set for list calls where resourceVersion is set See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions for details.\n\nDefaults to unset", + Type: []string{"string"}, + Format: "", + }, + }, + "timeoutSeconds": { + SchemaProps: spec.SchemaProps{ + Description: "Timeout for the list/watch call. This limits the duration of the call, regardless of any activity or inactivity.", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "limit": { + SchemaProps: spec.SchemaProps{ + Description: "limit is a maximum number of responses to return for a list call. If more items exist, the server will set the `continue` field on the list metadata to a value that can be used with the same initial query to retrieve the next set of results. Setting a limit may return fewer than the requested amount of items (up to zero items) in the event all requested objects are filtered out and clients should only use the presence of the continue field to determine whether more results are available. Servers may choose not to support the limit argument and will return all of the available results. If limit is specified and the continue field is empty, clients may assume that no more results are available. This field is not supported if watch is true.\n\nThe server guarantees that the objects returned when using continue will be identical to issuing a single list call without a limit - that is, no objects created, modified, or deleted after the first request is issued will be included in any subsequent continued requests. This is sometimes referred to as a consistent snapshot, and ensures that a client that is using limit to receive smaller chunks of a very large result can ensure they see all possible objects. If objects are updated during a chunked list the version of the object that was present at the time the first list result was calculated is returned.", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "continue": { + SchemaProps: spec.SchemaProps{ + Description: "The continue option should be set when retrieving more results from the server. Since this value is server defined, clients may only use the continue value from a previous query result with identical query parameters (except for the value of continue) and the server may reject a continue value it does not recognize. If the specified continue value is no longer valid whether due to expiration (generally five to fifteen minutes) or a configuration change on the server, the server will respond with a 410 ResourceExpired error together with a continue token. If the client needs a consistent list, it must restart their list without the continue field. Otherwise, the client may send another list request with the token received with the 410 error, the server will respond with a list starting from the next key, but from the latest snapshot, which is inconsistent from the previous list results - objects that are created, modified, or deleted after the first list request will be included in the response, as long as their keys are after the \"next key\".\n\nThis field is not supported when watch is true. Clients may start a watch from the last resourceVersion value returned by the server and not miss any modifications.", + Type: []string{"string"}, + Format: "", + }, + }, + "sendInitialEvents": { + SchemaProps: spec.SchemaProps{ + Description: "`sendInitialEvents=true` may be set together with `watch=true`. In that case, the watch stream will begin with synthetic events to produce the current state of objects in the collection. Once all such events have been sent, a synthetic \"Bookmark\" event will be sent. The bookmark will report the ResourceVersion (RV) corresponding to the set of objects, and be marked with `\"k8s.io/initial-events-end\": \"true\"` annotation. Afterwards, the watch stream will proceed as usual, sending watch events corresponding to changes (subsequent to the RV) to objects watched.\n\nWhen `sendInitialEvents` option is set, we require `resourceVersionMatch` option to also be set. The semantic of the watch request is as following: - `resourceVersionMatch` = NotOlderThan\n is interpreted as \"data at least as new as the provided `resourceVersion`\"\n and the bookmark event is send when the state is synced\n to a `resourceVersion` at least as fresh as the one provided by the ListOptions.\n If `resourceVersion` is unset, this is interpreted as \"consistent read\" and the\n bookmark event is send when the state is synced at least to the moment\n when request started being processed.\n- `resourceVersionMatch` set to any other value or unset\n Invalid error is returned.\n\nDefaults to true if `resourceVersion=\"\"` or `resourceVersion=\"0\"` (for backward compatibility reasons) and to false otherwise.", + Type: []string{"boolean"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_ManagedFieldsEntry(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ManagedFieldsEntry is a workflow-id, a FieldSet and the group version of the resource that the fieldset applies to.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "manager": { + SchemaProps: spec.SchemaProps{ + Description: "Manager is an identifier of the workflow managing these fields.", + Type: []string{"string"}, + Format: "", + }, + }, + "operation": { + SchemaProps: spec.SchemaProps{ + Description: "Operation is the type of operation which lead to this ManagedFieldsEntry being created. The only valid values for this field are 'Apply' and 'Update'.", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the version of this resource that this field set applies to. The format is \"group/version\" just like the top-level APIVersion field. It is necessary to track the version of a field set because it cannot be automatically converted.", + Type: []string{"string"}, + Format: "", + }, + }, + "time": { + SchemaProps: spec.SchemaProps{ + Description: "Time is the timestamp of when the ManagedFields entry was added. The timestamp will also be updated if a field is added, the manager changes any of the owned fields value or removes a field. The timestamp does not update when a field is removed from the entry because another manager took it over.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "fieldsType": { + SchemaProps: spec.SchemaProps{ + Description: "FieldsType is the discriminator for the different fields format and version. There is currently only one possible value: \"FieldsV1\"", + Type: []string{"string"}, + Format: "", + }, + }, + "fieldsV1": { + SchemaProps: spec.SchemaProps{ + Description: "FieldsV1 holds the first JSON version format as described in the \"FieldsV1\" type.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.FieldsV1"), + }, + }, + "subresource": { + SchemaProps: spec.SchemaProps{ + Description: "Subresource is the name of the subresource used to update that object, or empty string if the object was updated through the main resource. The value of this field is used to distinguish between managers, even if they share the same name. For example, a status update will be distinct from a regular update using the same manager name. Note that the APIVersion field is not related to the Subresource field and it always corresponds to the version of the main resource.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.FieldsV1", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_pkg_apis_meta_v1_MicroTime(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "MicroTime is version of Time with microsecond level precision.", + Type: v1.MicroTime{}.OpenAPISchemaType(), + Format: v1.MicroTime{}.OpenAPISchemaFormat(), + }, + }, + } +} + +func schema_pkg_apis_meta_v1_ObjectMeta(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ObjectMeta is metadata that all persisted resources must have, which includes all objects users must create.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names", + Type: []string{"string"}, + Format: "", + }, + }, + "generateName": { + SchemaProps: spec.SchemaProps{ + Description: "GenerateName is an optional prefix, used by the server, to generate a unique name ONLY IF the Name field has not been provided. If this field is used, the name returned to the client will be different than the name passed. This value will also be combined with a unique suffix. The provided value has the same validation rules as the Name field, and may be truncated by the length of the suffix required to make the value unique on the server.\n\nIf this field is specified and the generated name exists, the server will return a 409.\n\nApplied only if Name is not specified. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#idempotency", + Type: []string{"string"}, + Format: "", + }, + }, + "namespace": { + SchemaProps: spec.SchemaProps{ + Description: "Namespace defines the space within which each name must be unique. An empty namespace is equivalent to the \"default\" namespace, but \"default\" is the canonical representation. Not all objects are required to be scoped to a namespace - the value of this field for those objects will be empty.\n\nMust be a DNS_LABEL. Cannot be updated. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces", + Type: []string{"string"}, + Format: "", + }, + }, + "selfLink": { + SchemaProps: spec.SchemaProps{ + Description: "Deprecated: selfLink is a legacy read-only field that is no longer populated by the system.", + Type: []string{"string"}, + Format: "", + }, + }, + "uid": { + SchemaProps: spec.SchemaProps{ + Description: "UID is the unique in time and space value for this object. It is typically generated by the server on successful creation of a resource and is not allowed to change on PUT operations.\n\nPopulated by the system. Read-only. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids", + Type: []string{"string"}, + Format: "", + }, + }, + "resourceVersion": { + SchemaProps: spec.SchemaProps{ + Description: "An opaque value that represents the internal version of this object that can be used by clients to determine when objects have changed. May be used for optimistic concurrency, change detection, and the watch operation on a resource or set of resources. Clients must treat these values as opaque and passed unmodified back to the server. They may only be valid for a particular resource or set of resources.\n\nPopulated by the system. Read-only. Value must be treated as opaque by clients and . More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency", + Type: []string{"string"}, + Format: "", + }, + }, + "generation": { + SchemaProps: spec.SchemaProps{ + Description: "A sequence number representing a specific generation of the desired state. Populated by the system. Read-only.", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "creationTimestamp": { + SchemaProps: spec.SchemaProps{ + Description: "CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "deletionTimestamp": { + SchemaProps: spec.SchemaProps{ + Description: "DeletionTimestamp is RFC 3339 date and time at which this resource will be deleted. This field is set by the server when a graceful deletion is requested by the user, and is not directly settable by a client. The resource is expected to be deleted (no longer visible from resource lists, and not reachable by name) after the time in this field, once the finalizers list is empty. As long as the finalizers list contains items, deletion is blocked. Once the deletionTimestamp is set, this value may not be unset or be set further into the future, although it may be shortened or the resource may be deleted prior to this time. For example, a user may request that a pod is deleted in 30 seconds. The Kubelet will react by sending a graceful termination signal to the containers in the pod. After that 30 seconds, the Kubelet will send a hard termination signal (SIGKILL) to the container and after cleanup, remove the pod from the API. In the presence of network partitions, this object may still exist after this timestamp, until an administrator or automated process can determine the resource is fully terminated. If not set, graceful deletion of the object has not been requested.\n\nPopulated by the system when a graceful deletion is requested. Read-only. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.Time"), + }, + }, + "deletionGracePeriodSeconds": { + SchemaProps: spec.SchemaProps{ + Description: "Number of seconds allowed for this object to gracefully terminate before it will be removed from the system. Only set when deletionTimestamp is also set. May only be shortened. Read-only.", + Type: []string{"integer"}, + Format: "int64", + }, + }, + "labels": { + SchemaProps: spec.SchemaProps{ + Description: "Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "annotations": { + SchemaProps: spec.SchemaProps{ + Description: "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "ownerReferences": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "uid", + }, + "x-kubernetes-list-type": "map", + "x-kubernetes-patch-merge-key": "uid", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "List of objects depended by this object. If ALL objects in the list have been deleted, this object will be garbage collected. If this object is managed by a controller, then an entry in this list will point to this controller, with the controller field set to true. There cannot be more than one managing controller.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.OwnerReference"), + }, + }, + }, + }, + }, + "finalizers": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + "x-kubernetes-patch-strategy": "merge", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "Must be empty before the object is deleted from the registry. Each entry is an identifier for the responsible component that will remove the entry from the list. If the deletionTimestamp of the object is non-nil, entries in this list can only be removed. Finalizers may be processed and removed in any order. Order is NOT enforced because it introduces significant risk of stuck finalizers. finalizers is a shared field, any actor with permission can reorder it. If the finalizer list is processed in order, then this can lead to a situation in which the component responsible for the first finalizer in the list is waiting for a signal (field value, external system, or other) produced by a component responsible for a finalizer later in the list, resulting in a deadlock. Without enforced ordering finalizers are free to order amongst themselves and are not vulnerable to ordering changes in the list.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "managedFields": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "ManagedFields maps workflow-id and version to the set of fields that are managed by that workflow. This is mostly for internal housekeeping, and users typically shouldn't need to set or understand this field. A workflow can be the user's name, a controller's name, or the name of a specific apply path like \"ci-cd\". The set of fields is always in the version that the workflow used when modifying the object.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ManagedFieldsEntry"), + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ManagedFieldsEntry", "k8s.io/apimachinery/pkg/apis/meta/v1.OwnerReference", "k8s.io/apimachinery/pkg/apis/meta/v1.Time"}, + } +} + +func schema_pkg_apis_meta_v1_OwnerReference(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "OwnerReference contains enough information to let you identify an owning object. An owning object must be in the same namespace as the dependent, or be cluster-scoped, so there is no namespace field.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "API version of the referent.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind of the referent. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "name": { + SchemaProps: spec.SchemaProps{ + Description: "Name of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "uid": { + SchemaProps: spec.SchemaProps{ + Description: "UID of the referent. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "controller": { + SchemaProps: spec.SchemaProps{ + Description: "If true, this reference points to the managing controller.", + Type: []string{"boolean"}, + Format: "", + }, + }, + "blockOwnerDeletion": { + SchemaProps: spec.SchemaProps{ + Description: "If true, AND if the owner has the \"foregroundDeletion\" finalizer, then the owner cannot be deleted from the key-value store until this reference is removed. See https://kubernetes.io/docs/concepts/architecture/garbage-collection/#foreground-deletion for how the garbage collector interacts with this field and enforces the foreground deletion. Defaults to false. To set this field, a user needs \"delete\" permission of the owner, otherwise 422 (Unprocessable Entity) will be returned.", + Type: []string{"boolean"}, + Format: "", + }, + }, + }, + Required: []string{"apiVersion", "kind", "name", "uid"}, + }, + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-map-type": "atomic", + }, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_PartialObjectMetadata(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PartialObjectMetadata is a generic representation of any object with ObjectMeta. It allows clients to get access to a particular ObjectMeta schema without knowing the details of the version.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "Standard object's metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"}, + } +} + +func schema_pkg_apis_meta_v1_PartialObjectMetadataList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PartialObjectMetadataList contains a list of objects containing only their metadata", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Description: "items contains each of the included items.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.PartialObjectMetadata"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "k8s.io/apimachinery/pkg/apis/meta/v1.PartialObjectMetadata"}, + } +} + +func schema_pkg_apis_meta_v1_Patch(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Patch is provided to give a concrete name and type to the Kubernetes PATCH request body.", + Type: []string{"object"}, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_PatchOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "PatchOptions may be provided when patching an API object. PatchOptions is meant to be a superset of UpdateOptions.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "dryRun": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "force": { + SchemaProps: spec.SchemaProps{ + Description: "Force is going to \"force\" Apply requests. It means user will re-acquire conflicting fields owned by other people. Force flag must be unset for non-apply patch requests.", + Type: []string{"boolean"}, + Format: "", + }, + }, + "fieldManager": { + SchemaProps: spec.SchemaProps{ + Description: "fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint. This field is required for apply requests (application/apply-patch) but optional for non-apply patch types (JsonPatch, MergePatch, StrategicMergePatch).", + Type: []string{"string"}, + Format: "", + }, + }, + "fieldValidation": { + SchemaProps: spec.SchemaProps{ + Description: "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_Preconditions(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Preconditions must be fulfilled before an operation (update, delete, etc.) is carried out.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "uid": { + SchemaProps: spec.SchemaProps{ + Description: "Specifies the target UID.", + Type: []string{"string"}, + Format: "", + }, + }, + "resourceVersion": { + SchemaProps: spec.SchemaProps{ + Description: "Specifies the target ResourceVersion", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_RootPaths(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "RootPaths lists the paths available at root. For example: \"/healthz\", \"/apis\".", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "paths": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "paths are the paths available at root.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + Required: []string{"paths"}, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_ServerAddressByClientCIDR(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ServerAddressByClientCIDR helps the client to determine the server address that they should use, depending on the clientCIDR that they match.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "clientCIDR": { + SchemaProps: spec.SchemaProps{ + Description: "The CIDR with which clients can match their IP to figure out the server address that they should use.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "serverAddress": { + SchemaProps: spec.SchemaProps{ + Description: "Address of this server, suitable for a client that matches the above CIDR. This can be a hostname, hostname:port, IP or IP:port.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"clientCIDR", "serverAddress"}, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_Status(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Status is a return value for calls that don't return other objects.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "Status of the operation. One of: \"Success\" or \"Failure\". More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status", + Type: []string{"string"}, + Format: "", + }, + }, + "message": { + SchemaProps: spec.SchemaProps{ + Description: "A human-readable description of the status of this operation.", + Type: []string{"string"}, + Format: "", + }, + }, + "reason": { + SchemaProps: spec.SchemaProps{ + Description: "A machine-readable description of why this operation is in the \"Failure\" status. If this value is empty there is no information available. A Reason clarifies an HTTP status code but does not override it.", + Type: []string{"string"}, + Format: "", + }, + }, + "details": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "Extended data associated with the reason. Each reason may define its own extended details. This field is optional and the data returned is not guaranteed to conform to any schema except that defined by the reason type.", + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.StatusDetails"), + }, + }, + "code": { + SchemaProps: spec.SchemaProps{ + Description: "Suggested HTTP return code for this status, 0 if not set.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "k8s.io/apimachinery/pkg/apis/meta/v1.StatusDetails"}, + } +} + +func schema_pkg_apis_meta_v1_StatusCause(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "StatusCause provides more information about an api.Status failure, including cases when multiple errors are encountered.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "reason": { + SchemaProps: spec.SchemaProps{ + Description: "A machine-readable description of the cause of the error. If this value is empty there is no information available.", + Type: []string{"string"}, + Format: "", + }, + }, + "message": { + SchemaProps: spec.SchemaProps{ + Description: "A human-readable description of the cause of the error. This field may be presented as-is to a reader.", + Type: []string{"string"}, + Format: "", + }, + }, + "field": { + SchemaProps: spec.SchemaProps{ + Description: "The field of the resource that has caused this error, as named by its JSON serialization. May include dot and postfix notation for nested attributes. Arrays are zero-indexed. Fields may appear more than once in an array of causes due to fields having multiple errors. Optional.\n\nExamples:\n \"name\" - the field \"name\" on the current resource\n \"items[0].name\" - the field \"name\" on the first array entry in \"items\"", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_StatusDetails(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "StatusDetails is a set of additional properties that MAY be set by the server to provide additional information about a response. The Reason field of a Status object defines what attributes will be set. Clients must ignore fields that do not match the defined type of each attribute, and should assume that any attribute may be empty, invalid, or under defined.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "The name attribute of the resource associated with the status StatusReason (when there is a single name which can be described).", + Type: []string{"string"}, + Format: "", + }, + }, + "group": { + SchemaProps: spec.SchemaProps{ + Description: "The group attribute of the resource associated with the status StatusReason.", + Type: []string{"string"}, + Format: "", + }, + }, + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "The kind attribute of the resource associated with the status StatusReason. On some operations may differ from the requested resource Kind. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "uid": { + SchemaProps: spec.SchemaProps{ + Description: "UID of the resource. (when there is a single resource which can be described). More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#uids", + Type: []string{"string"}, + Format: "", + }, + }, + "causes": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "The Causes array includes more details associated with the StatusReason failure. Not all StatusReasons may provide detailed causes.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.StatusCause"), + }, + }, + }, + }, + }, + "retryAfterSeconds": { + SchemaProps: spec.SchemaProps{ + Description: "If specified, the time in seconds before the operation should be retried. Some errors may indicate the client must take an alternate action - for those errors this field may indicate how long to wait before taking the alternate action.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.StatusCause"}, + } +} + +func schema_pkg_apis_meta_v1_Table(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Table is a tabular representation of a set of API resources. The server transforms the object into a set of preferred columns for quickly reviewing the objects.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Description: "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "columnDefinitions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "columnDefinitions describes each column in the returned items array. The number of cells per row will always match the number of column definitions.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.TableColumnDefinition"), + }, + }, + }, + }, + }, + "rows": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "rows is the list of items in the table.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.TableRow"), + }, + }, + }, + }, + }, + }, + Required: []string{"columnDefinitions", "rows"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "k8s.io/apimachinery/pkg/apis/meta/v1.TableColumnDefinition", "k8s.io/apimachinery/pkg/apis/meta/v1.TableRow"}, + } +} + +func schema_pkg_apis_meta_v1_TableColumnDefinition(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TableColumnDefinition contains information about a column returned in the Table.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "name": { + SchemaProps: spec.SchemaProps{ + Description: "name is a human readable name for the column.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "type": { + SchemaProps: spec.SchemaProps{ + Description: "type is an OpenAPI type definition for this column, such as number, integer, string, or array. See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for more.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "format": { + SchemaProps: spec.SchemaProps{ + Description: "format is an optional OpenAPI type modifier for this column. A format modifies the type and imposes additional rules, like date or time formatting for a string. The 'name' format is applied to the primary identifier column which has type 'string' to assist in clients identifying column is the resource name. See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md#data-types for more.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "description": { + SchemaProps: spec.SchemaProps{ + Description: "description is a human readable description of this column.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "priority": { + SchemaProps: spec.SchemaProps{ + Description: "priority is an integer defining the relative importance of this column compared to others. Lower numbers are considered higher priority. Columns that may be omitted in limited space scenarios should be given a higher priority.", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + Required: []string{"name", "type", "format", "description", "priority"}, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_TableOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TableOptions are used when a Table is requested by the caller.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "includeObject": { + SchemaProps: spec.SchemaProps{ + Description: "includeObject decides whether to include each object along with its columnar information. Specifying \"None\" will return no object, specifying \"Object\" will return the full object contents, and specifying \"Metadata\" (the default) will return the object's metadata in the PartialObjectMetadata kind in version v1beta1 of the meta.k8s.io API group.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_TableRow(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TableRow is an individual row in a table.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "cells": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "cells will be as wide as the column definitions array and may contain strings, numbers (float64 or int64), booleans, simple maps, lists, or null. See the type field of the column definition for a more detailed description.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Format: "", + }, + }, + }, + }, + }, + "conditions": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "conditions describe additional status of a row that are relevant for a human user. These conditions apply to the row, not to the object, and will be specific to table output. The only defined condition type is 'Completed', for a row that indicates a resource that has run to completion and can be given less visual priority.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.TableRowCondition"), + }, + }, + }, + }, + }, + "object": { + SchemaProps: spec.SchemaProps{ + Description: "This field contains the requested additional information about each object based on the includeObject policy when requesting the Table. If \"None\", this field is empty, if \"Object\" this will be the default serialization of the object for the current API version, and if \"Metadata\" (the default) will contain the object metadata. Check the returned kind and apiVersion of the object before parsing. The media type of the object will always match the enclosing list - if this as a JSON table, these will be JSON encoded objects.", + Ref: ref("k8s.io/apimachinery/pkg/runtime.RawExtension"), + }, + }, + }, + Required: []string{"cells"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.TableRowCondition", "k8s.io/apimachinery/pkg/runtime.RawExtension"}, + } +} + +func schema_pkg_apis_meta_v1_TableRowCondition(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TableRowCondition allows a row to be marked with additional information.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "type": { + SchemaProps: spec.SchemaProps{ + Description: "Type of row condition. The only defined value is 'Completed' indicating that the object this row represents has reached a completed state and may be given less visual priority than other rows. Clients are not required to honor any conditions but should be consistent where possible about handling the conditions.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "Status of the condition, one of True, False, Unknown.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "reason": { + SchemaProps: spec.SchemaProps{ + Description: "(brief) machine readable reason for the condition's last transition.", + Type: []string{"string"}, + Format: "", + }, + }, + "message": { + SchemaProps: spec.SchemaProps{ + Description: "Human readable message indicating details about last transition.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"type", "status"}, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_Time(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Time is a wrapper around time.Time which supports correct marshaling to YAML and JSON. Wrappers are provided for many of the factory methods that the time package offers.", + Type: v1.Time{}.OpenAPISchemaType(), + Format: v1.Time{}.OpenAPISchemaFormat(), + }, + }, + } +} + +func schema_pkg_apis_meta_v1_Timestamp(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Timestamp is a struct that is equivalent to Time, but intended for protobuf marshalling/unmarshalling. It is generated into a serialization that matches Time. Do not use in Go structs.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "seconds": { + SchemaProps: spec.SchemaProps{ + Description: "Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive.", + Default: 0, + Type: []string{"integer"}, + Format: "int64", + }, + }, + "nanos": { + SchemaProps: spec.SchemaProps{ + Description: "Non-negative fractions of a second at nanosecond resolution. Negative second values with fractions must still have non-negative nanos values that count forward in time. Must be from 0 to 999,999,999 inclusive. This field may be limited in precision depending on context.", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + Required: []string{"seconds", "nanos"}, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_TypeMeta(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TypeMeta describes an individual object in an API response or request with strings representing the type of the object and its API schema version. Structures that are versioned or persisted should inline TypeMeta.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_UpdateOptions(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "UpdateOptions may be provided when updating an API object. All fields in UpdateOptions should also be present in PatchOptions.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "dryRun": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "When present, indicates that modifications should not be persisted. An invalid or unrecognized dryRun directive will result in an error response and no further processing of the request. Valid values are: - All: all dry run stages will be processed", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "fieldManager": { + SchemaProps: spec.SchemaProps{ + Description: "fieldManager is a name associated with the actor or entity that is making these changes. The value must be less than or 128 characters long, and only contain printable characters, as defined by https://golang.org/pkg/unicode/#IsPrint.", + Type: []string{"string"}, + Format: "", + }, + }, + "fieldValidation": { + SchemaProps: spec.SchemaProps{ + Description: "fieldValidation instructs the server on how to handle objects in the request (POST/PUT/PATCH) containing unknown or duplicate fields. Valid values are: - Ignore: This will ignore any unknown fields that are silently dropped from the object, and will ignore all but the last duplicate field that the decoder encounters. This is the default behavior prior to v1.23. - Warn: This will send a warning via the standard warning response header for each unknown field that is dropped from the object, and for each duplicate field that is encountered. The request will still succeed if there are no other errors, and will only persist the last of any duplicate fields. This is the default in v1.23+ - Strict: This will fail the request with a BadRequest error if any unknown fields would be dropped from the object, or if any duplicate fields are present. The error returned from the server will contain all unknown and duplicate fields encountered.", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_pkg_apis_meta_v1_WatchEvent(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Event represents a single event to a watched resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "type": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "object": { + SchemaProps: spec.SchemaProps{ + Description: "Object is:\n * If Type is Added or Modified: the new state of the object.\n * If Type is Deleted: the state of the object immediately before deletion.\n * If Type is Error: *Status is recommended; other types may make sense\n depending on context.", + Ref: ref("k8s.io/apimachinery/pkg/runtime.RawExtension"), + }, + }, + }, + Required: []string{"type", "object"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/runtime.RawExtension"}, + } +} + +func schema_k8sio_apimachinery_pkg_runtime_RawExtension(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "RawExtension is used to hold extensions in external versions.\n\nTo use this, make a field which has RawExtension as its type in your external, versioned struct, and Object in your internal struct. You also need to register your various plugin types.\n\n// Internal package:\n\n\ttype MyAPIObject struct {\n\t\truntime.TypeMeta `json:\",inline\"`\n\t\tMyPlugin runtime.Object `json:\"myPlugin\"`\n\t}\n\n\ttype PluginA struct {\n\t\tAOption string `json:\"aOption\"`\n\t}\n\n// External package:\n\n\ttype MyAPIObject struct {\n\t\truntime.TypeMeta `json:\",inline\"`\n\t\tMyPlugin runtime.RawExtension `json:\"myPlugin\"`\n\t}\n\n\ttype PluginA struct {\n\t\tAOption string `json:\"aOption\"`\n\t}\n\n// On the wire, the JSON will look something like this:\n\n\t{\n\t\t\"kind\":\"MyAPIObject\",\n\t\t\"apiVersion\":\"v1\",\n\t\t\"myPlugin\": {\n\t\t\t\"kind\":\"PluginA\",\n\t\t\t\"aOption\":\"foo\",\n\t\t},\n\t}\n\nSo what happens? Decode first uses json or yaml to unmarshal the serialized data into your external MyAPIObject. That causes the raw JSON to be stored, but not unpacked. The next step is to copy (using pkg/conversion) into the internal struct. The runtime package's DefaultScheme has conversion functions installed which will unpack the JSON stored in RawExtension, turning it into the correct object type, and storing it in the Object. (TODO: In the case where the object is of an unknown type, a runtime.Unknown object will be created and stored.)", + Type: []string{"object"}, + }, + }, + } +} + +func schema_k8sio_apimachinery_pkg_runtime_TypeMeta(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TypeMeta is shared by all top level objects. The proper way to use it is to inline it in your type, like this:\n\n\ttype MyAwesomeAPIObject struct {\n\t runtime.TypeMeta `json:\",inline\"`\n\t ... // other fields\n\t}\n\nfunc (obj *MyAwesomeAPIObject) SetGroupVersionKind(gvk *metav1.GroupVersionKind) { metav1.UpdateTypeMeta(obj,gvk) }; GroupVersionKind() *GroupVersionKind\n\nTypeMeta is provided here for convenience. You may use it directly from this package or define your own with the same fields.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "kind": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + +func schema_k8sio_apimachinery_pkg_runtime_Unknown(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Unknown allows api objects with unknown types to be passed-through. This can be used to deal with the API objects from a plug-in. Unknown objects still have functioning TypeMeta features-- kind, version, etc. metadata and field mutatation.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "kind": { + SchemaProps: spec.SchemaProps{ + Type: []string{"string"}, + Format: "", + }, + }, + "ContentEncoding": { + SchemaProps: spec.SchemaProps{ + Description: "ContentEncoding is encoding used to encode 'Raw' data. Unspecified means no encoding.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "ContentType": { + SchemaProps: spec.SchemaProps{ + Description: "ContentType is serialization method used to serialize 'Raw'. Unspecified means ContentTypeJSON.", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"ContentEncoding", "ContentType"}, + }, + }, + } +} + +func schema_k8sio_apimachinery_pkg_version_Info(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Info contains versioning information. how we'll want to distribute that information.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "major": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "minor": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "gitVersion": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "gitCommit": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "gitTreeState": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "buildDate": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "goVersion": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "compiler": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "platform": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"major", "minor", "gitVersion", "gitCommit", "gitTreeState", "buildDate", "goVersion", "compiler", "platform"}, + }, + }, + } +} + +func schema_apiserver_apis_core_v1_TestType(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TestType is a top-level type. A client is created for it.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/code-generator/examples/apiserver/apis/core/v1.TestTypeStatus"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta", "k8s.io/code-generator/examples/apiserver/apis/core/v1.TestTypeStatus"}, + } +} + +func schema_apiserver_apis_core_v1_TestTypeList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TestTypeList is a top-level list type. The client methods for lists are automatically created. You are not supposed to create a separated client for this one.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/code-generator/examples/apiserver/apis/core/v1.TestType"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "k8s.io/code-generator/examples/apiserver/apis/core/v1.TestType"}, + } +} + +func schema_apiserver_apis_core_v1_TestTypeStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "blah": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"blah"}, + }, + }, + } +} + +func schema_apiserver_apis_example_v1_TestType(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TestType is a top-level type. A client is created for it.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/code-generator/examples/apiserver/apis/example/v1.TestTypeStatus"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta", "k8s.io/code-generator/examples/apiserver/apis/example/v1.TestTypeStatus"}, + } +} + +func schema_apiserver_apis_example_v1_TestTypeList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TestTypeList is a top-level list type. The client methods for lists are automatically created. You are not supposed to create a separated client for this one.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/code-generator/examples/apiserver/apis/example/v1.TestType"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "k8s.io/code-generator/examples/apiserver/apis/example/v1.TestType"}, + } +} + +func schema_apiserver_apis_example_v1_TestTypeStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "blah": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"blah"}, + }, + }, + } +} + +func schema_apiserver_apis_example2_v1_TestType(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TestType is a top-level type. A client is created for it.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/code-generator/examples/apiserver/apis/example2/v1.TestTypeStatus"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta", "k8s.io/code-generator/examples/apiserver/apis/example2/v1.TestTypeStatus"}, + } +} + +func schema_apiserver_apis_example2_v1_TestTypeList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TestTypeList is a top-level list type. The client methods for lists are automatically created. You are not supposed to create a separated client for this one.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/code-generator/examples/apiserver/apis/example2/v1.TestType"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "k8s.io/code-generator/examples/apiserver/apis/example2/v1.TestType"}, + } +} + +func schema_apiserver_apis_example2_v1_TestTypeStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "blah": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"blah"}, + }, + }, + } +} + +func schema_apiserver_apis_example3io_v1_TestType(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TestType is a top-level type. A client is created for it.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/code-generator/examples/apiserver/apis/example3.io/v1.TestTypeStatus"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta", "k8s.io/code-generator/examples/apiserver/apis/example3.io/v1.TestTypeStatus"}, + } +} + +func schema_apiserver_apis_example3io_v1_TestTypeList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TestTypeList is a top-level list type. The client methods for lists are automatically created. You are not supposed to create a separated client for this one.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/code-generator/examples/apiserver/apis/example3.io/v1.TestType"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "k8s.io/code-generator/examples/apiserver/apis/example3.io/v1.TestType"}, + } +} + +func schema_apiserver_apis_example3io_v1_TestTypeStatus(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "blah": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + Required: []string{"blah"}, + }, + }, + } +} diff --git a/code-generator/examples/crd/apis/conflicting/v1/doc.go b/code-generator/examples/crd/apis/conflicting/v1/doc.go new file mode 100644 index 000000000..3fa9b9461 --- /dev/null +++ b/code-generator/examples/crd/apis/conflicting/v1/doc.go @@ -0,0 +1,22 @@ +/* +Copyright 2024 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:defaulter-gen=TypeMeta +// +groupName=conflicting.test.crd.code-generator.k8s.io +// +groupGoName=ConflictingExample + +package v1 // import "k8s.io/code-generator/examples/crd/apis/conflicting/v1" diff --git a/code-generator/examples/crd/apis/conflicting/v1/register.go b/code-generator/examples/crd/apis/conflicting/v1/register.go new file mode 100644 index 000000000..1f2d6d85f --- /dev/null +++ b/code-generator/examples/crd/apis/conflicting/v1/register.go @@ -0,0 +1,59 @@ +/* +Copyright 2015 The Kubernetes 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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "conflicting.test.crd.code-generator.k8s.io", Version: "v1"} + +var ( + // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to api.Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion, + &metav1.Status{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/code-generator/examples/crd/apis/conflicting/v1/types.go b/code-generator/examples/crd/apis/conflicting/v1/types.go new file mode 100644 index 000000000..12e63b54c --- /dev/null +++ b/code-generator/examples/crd/apis/conflicting/v1/types.go @@ -0,0 +1,56 @@ +/* +Copyright 2015 The Kubernetes 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 v1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status TestTypeStatus `json:"status,omitempty"` + + TestEmbeddedType `json:"embedded"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separate client for this one. +type TestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []TestType `json:"items"` +} + +type TestTypeStatus struct { + Blah string `json:"blah"` +} + +// TestEmbeddedType is a type intended to create conflicts with other embedded structs: +// Kind conflicts with TypeMeta (inlined), and Namespace conflicts with ObjectMeta (embedded). +type TestEmbeddedType struct { + Kind string `json:"kind"` + Namespace string `json:"namespace"` +} diff --git a/pkg/apis/samplecontroller/v1alpha1/zz_generated.deepcopy.go b/code-generator/examples/crd/apis/conflicting/v1/zz_generated.deepcopy.go similarity index 73% rename from pkg/apis/samplecontroller/v1alpha1/zz_generated.deepcopy.go rename to code-generator/examples/crd/apis/conflicting/v1/zz_generated.deepcopy.go index 26194609e..a73a4d908 100644 --- a/pkg/apis/samplecontroller/v1alpha1/zz_generated.deepcopy.go +++ b/code-generator/examples/crd/apis/conflicting/v1/zz_generated.deepcopy.go @@ -19,34 +19,50 @@ limitations under the License. // Code generated by deepcopy-gen. DO NOT EDIT. -package v1alpha1 +package v1 import ( runtime "k8s.io/apimachinery/pkg/runtime" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *Foo) DeepCopyInto(out *Foo) { +func (in *TestEmbeddedType) DeepCopyInto(out *TestEmbeddedType) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestEmbeddedType. +func (in *TestEmbeddedType) DeepCopy() *TestEmbeddedType { + if in == nil { + return nil + } + out := new(TestEmbeddedType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - in.Spec.DeepCopyInto(&out.Spec) out.Status = in.Status + out.TestEmbeddedType = in.TestEmbeddedType return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Foo. -func (in *Foo) DeepCopy() *Foo { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { if in == nil { return nil } - out := new(Foo) + out := new(TestType) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *Foo) DeepCopyObject() runtime.Object { +func (in *TestType) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -54,13 +70,13 @@ func (in *Foo) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FooList) DeepCopyInto(out *FooList) { +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { *out = *in out.TypeMeta = in.TypeMeta in.ListMeta.DeepCopyInto(&out.ListMeta) if in.Items != nil { in, out := &in.Items, &out.Items - *out = make([]Foo, len(*in)) + *out = make([]TestType, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } @@ -68,18 +84,18 @@ func (in *FooList) DeepCopyInto(out *FooList) { return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooList. -func (in *FooList) DeepCopy() *FooList { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { if in == nil { return nil } - out := new(FooList) + out := new(TestTypeList) in.DeepCopyInto(out) return out } // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. -func (in *FooList) DeepCopyObject() runtime.Object { +func (in *TestTypeList) DeepCopyObject() runtime.Object { if c := in.DeepCopy(); c != nil { return c } @@ -87,38 +103,17 @@ func (in *FooList) DeepCopyObject() runtime.Object { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FooSpec) DeepCopyInto(out *FooSpec) { - *out = *in - if in.Replicas != nil { - in, out := &in.Replicas, &out.Replicas - *out = new(int32) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooSpec. -func (in *FooSpec) DeepCopy() *FooSpec { - if in == nil { - return nil - } - out := new(FooSpec) - in.DeepCopyInto(out) - return out -} - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *FooStatus) DeepCopyInto(out *FooStatus) { +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { *out = *in return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FooStatus. -func (in *FooStatus) DeepCopy() *FooStatus { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { if in == nil { return nil } - out := new(FooStatus) + out := new(TestTypeStatus) in.DeepCopyInto(out) return out } diff --git a/code-generator/examples/crd/apis/conflicting/v1/zz_generated.defaults.go b/code-generator/examples/crd/apis/conflicting/v1/zz_generated.defaults.go new file mode 100644 index 000000000..dac177e93 --- /dev/null +++ b/code-generator/examples/crd/apis/conflicting/v1/zz_generated.defaults.go @@ -0,0 +1,33 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/code-generator/examples/crd/apis/example/v1/doc.go b/code-generator/examples/crd/apis/example/v1/doc.go new file mode 100644 index 000000000..89647413b --- /dev/null +++ b/code-generator/examples/crd/apis/example/v1/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2016 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:defaulter-gen=TypeMeta +// +groupName=example.crd.code-generator.k8s.io + +package v1 // import "k8s.io/code-generator/examples/crd/apis/example/v1" diff --git a/code-generator/examples/crd/apis/example/v1/register.go b/code-generator/examples/crd/apis/example/v1/register.go new file mode 100644 index 000000000..58371e0e9 --- /dev/null +++ b/code-generator/examples/crd/apis/example/v1/register.go @@ -0,0 +1,59 @@ +/* +Copyright 2015 The Kubernetes 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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.crd.code-generator.k8s.io", Version: "v1"} + +var ( + // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion, + &metav1.Status{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/code-generator/examples/crd/apis/example/v1/types.go b/code-generator/examples/crd/apis/example/v1/types.go new file mode 100644 index 000000000..0fc1edb41 --- /dev/null +++ b/code-generator/examples/crd/apis/example/v1/types.go @@ -0,0 +1,77 @@ +/* +Copyright 2015 The Kubernetes 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 v1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +genclient:method=GetClusterTestType,verb=get +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status TestTypeStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []TestType `json:"items"` +} + +type TestTypeStatus struct { + Blah string `json:"blah"` +} + +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type ClusterTestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []ClusterTestType `json:"items"` +} + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient:method=GetScale,verb=get,subresource=scale,result=k8s.io/api/autoscaling/v1.Scale +// +genclient:method=UpdateScale,verb=update,subresource=scale,input=k8s.io/api/autoscaling/v1.Scale,result=k8s.io/api/autoscaling/v1.Scale + +type ClusterTestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status ClusterTestTypeStatus `json:"status,omitempty"` +} + +type ClusterTestTypeStatus struct { + Blah string `json:"blah"` +} diff --git a/code-generator/examples/crd/apis/example/v1/zz_generated.deepcopy.go b/code-generator/examples/crd/apis/example/v1/zz_generated.deepcopy.go new file mode 100644 index 000000000..5eee47016 --- /dev/null +++ b/code-generator/examples/crd/apis/example/v1/zz_generated.deepcopy.go @@ -0,0 +1,178 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestType) DeepCopyInto(out *ClusterTestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestType. +func (in *ClusterTestType) DeepCopy() *ClusterTestType { + if in == nil { + return nil + } + out := new(ClusterTestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterTestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestTypeList) DeepCopyInto(out *ClusterTestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ClusterTestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestTypeList. +func (in *ClusterTestTypeList) DeepCopy() *ClusterTestTypeList { + if in == nil { + return nil + } + out := new(ClusterTestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterTestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestTypeStatus) DeepCopyInto(out *ClusterTestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestTypeStatus. +func (in *ClusterTestTypeStatus) DeepCopy() *ClusterTestTypeStatus { + if in == nil { + return nil + } + out := new(ClusterTestTypeStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/examples/crd/apis/example/v1/zz_generated.defaults.go b/code-generator/examples/crd/apis/example/v1/zz_generated.defaults.go new file mode 100644 index 000000000..dac177e93 --- /dev/null +++ b/code-generator/examples/crd/apis/example/v1/zz_generated.defaults.go @@ -0,0 +1,33 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/code-generator/examples/crd/apis/example2/v1/doc.go b/code-generator/examples/crd/apis/example2/v1/doc.go new file mode 100644 index 000000000..0f962c8b1 --- /dev/null +++ b/code-generator/examples/crd/apis/example2/v1/doc.go @@ -0,0 +1,22 @@ +/* +Copyright 2016 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:defaulter-gen=TypeMeta +// +groupName=example.test.crd.code-generator.k8s.io +// +groupGoName=SecondExample + +package v1 // import "k8s.io/code-generator/examples/crd/apis/example2/v1" diff --git a/code-generator/examples/crd/apis/example2/v1/register.go b/code-generator/examples/crd/apis/example2/v1/register.go new file mode 100644 index 000000000..d0a852a31 --- /dev/null +++ b/code-generator/examples/crd/apis/example2/v1/register.go @@ -0,0 +1,59 @@ +/* +Copyright 2015 The Kubernetes 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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.test.crd.code-generator.k8s.io", Version: "v1"} + +var ( + // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to api.Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion, + &metav1.Status{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/code-generator/examples/crd/apis/example2/v1/types.go b/code-generator/examples/crd/apis/example2/v1/types.go new file mode 100644 index 000000000..24a1a348c --- /dev/null +++ b/code-generator/examples/crd/apis/example2/v1/types.go @@ -0,0 +1,47 @@ +/* +Copyright 2015 The Kubernetes 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 v1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status TestTypeStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []TestType `json:"items"` +} + +type TestTypeStatus struct { + Blah string `json:"blah"` +} diff --git a/code-generator/examples/crd/apis/example2/v1/zz_generated.deepcopy.go b/code-generator/examples/crd/apis/example2/v1/zz_generated.deepcopy.go new file mode 100644 index 000000000..d87f706f7 --- /dev/null +++ b/code-generator/examples/crd/apis/example2/v1/zz_generated.deepcopy.go @@ -0,0 +1,102 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/examples/crd/apis/example2/v1/zz_generated.defaults.go b/code-generator/examples/crd/apis/example2/v1/zz_generated.defaults.go new file mode 100644 index 000000000..dac177e93 --- /dev/null +++ b/code-generator/examples/crd/apis/example2/v1/zz_generated.defaults.go @@ -0,0 +1,33 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/code-generator/examples/crd/applyconfiguration/conflicting/v1/testembeddedtype.go b/code-generator/examples/crd/applyconfiguration/conflicting/v1/testembeddedtype.go new file mode 100644 index 000000000..c3ed08e18 --- /dev/null +++ b/code-generator/examples/crd/applyconfiguration/conflicting/v1/testembeddedtype.go @@ -0,0 +1,48 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// TestEmbeddedTypeApplyConfiguration represents a declarative configuration of the TestEmbeddedType type for use +// with apply. +type TestEmbeddedTypeApplyConfiguration struct { + Kind *string `json:"kind,omitempty"` + Namespace *string `json:"namespace,omitempty"` +} + +// TestEmbeddedTypeApplyConfiguration constructs a declarative configuration of the TestEmbeddedType type for use with +// apply. +func TestEmbeddedType() *TestEmbeddedTypeApplyConfiguration { + return &TestEmbeddedTypeApplyConfiguration{} +} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *TestEmbeddedTypeApplyConfiguration) WithKind(value string) *TestEmbeddedTypeApplyConfiguration { + b.Kind = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *TestEmbeddedTypeApplyConfiguration) WithNamespace(value string) *TestEmbeddedTypeApplyConfiguration { + b.Namespace = &value + return b +} diff --git a/code-generator/examples/crd/applyconfiguration/conflicting/v1/testtype.go b/code-generator/examples/crd/applyconfiguration/conflicting/v1/testtype.go new file mode 100644 index 000000000..167efe37a --- /dev/null +++ b/code-generator/examples/crd/applyconfiguration/conflicting/v1/testtype.go @@ -0,0 +1,223 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +import ( + apismetav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + metav1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// TestTypeApplyConfiguration represents a declarative configuration of the TestType type for use +// with apply. +type TestTypeApplyConfiguration struct { + metav1.TypeMetaApplyConfiguration `json:",inline"` + *metav1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Status *TestTypeStatusApplyConfiguration `json:"status,omitempty"` + *TestEmbeddedTypeApplyConfiguration `json:"embedded,omitempty"` +} + +// TestType constructs a declarative configuration of the TestType type for use with +// apply. +func TestType(name, namespace string) *TestTypeApplyConfiguration { + b := &TestTypeApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("TestType") + b.WithAPIVersion("conflicting.test.crd.code-generator.k8s.io/v1") + return b +} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithKind(value string) *TestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithAPIVersion(value string) *TestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithName(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithGenerateName(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithNamespace(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithUID(value types.UID) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithResourceVersion(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithGeneration(value int64) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithCreationTimestamp(value apismetav1.Time) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithDeletionTimestamp(value apismetav1.Time) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *TestTypeApplyConfiguration) WithLabels(entries map[string]string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *TestTypeApplyConfiguration) WithAnnotations(entries map[string]string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *TestTypeApplyConfiguration) WithOwnerReferences(values ...*metav1.OwnerReferenceApplyConfiguration) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *TestTypeApplyConfiguration) WithFinalizers(values ...string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *TestTypeApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &metav1.ObjectMetaApplyConfiguration{} + } +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithStatus(value *TestTypeStatusApplyConfiguration) *TestTypeApplyConfiguration { + b.Status = value + return b +} + +func (b *TestTypeApplyConfiguration) ensureTestEmbeddedTypeApplyConfigurationExists() { + if b.TestEmbeddedTypeApplyConfiguration == nil { + b.TestEmbeddedTypeApplyConfiguration = &TestEmbeddedTypeApplyConfiguration{} + } +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *TestTypeApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} diff --git a/code-generator/examples/crd/applyconfiguration/conflicting/v1/testtypestatus.go b/code-generator/examples/crd/applyconfiguration/conflicting/v1/testtypestatus.go new file mode 100644 index 000000000..246b2ee18 --- /dev/null +++ b/code-generator/examples/crd/applyconfiguration/conflicting/v1/testtypestatus.go @@ -0,0 +1,39 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// TestTypeStatusApplyConfiguration represents a declarative configuration of the TestTypeStatus type for use +// with apply. +type TestTypeStatusApplyConfiguration struct { + Blah *string `json:"blah,omitempty"` +} + +// TestTypeStatusApplyConfiguration constructs a declarative configuration of the TestTypeStatus type for use with +// apply. +func TestTypeStatus() *TestTypeStatusApplyConfiguration { + return &TestTypeStatusApplyConfiguration{} +} + +// WithBlah sets the Blah field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Blah field is set to the value of the last call. +func (b *TestTypeStatusApplyConfiguration) WithBlah(value string) *TestTypeStatusApplyConfiguration { + b.Blah = &value + return b +} diff --git a/code-generator/examples/crd/applyconfiguration/example/v1/clustertesttype.go b/code-generator/examples/crd/applyconfiguration/example/v1/clustertesttype.go new file mode 100644 index 000000000..49ceb182a --- /dev/null +++ b/code-generator/examples/crd/applyconfiguration/example/v1/clustertesttype.go @@ -0,0 +1,215 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +import ( + apismetav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + metav1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// ClusterTestTypeApplyConfiguration represents a declarative configuration of the ClusterTestType type for use +// with apply. +type ClusterTestTypeApplyConfiguration struct { + metav1.TypeMetaApplyConfiguration `json:",inline"` + *metav1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Status *ClusterTestTypeStatusApplyConfiguration `json:"status,omitempty"` +} + +// ClusterTestType constructs a declarative configuration of the ClusterTestType type for use with +// apply. +func ClusterTestType(name string) *ClusterTestTypeApplyConfiguration { + b := &ClusterTestTypeApplyConfiguration{} + b.WithName(name) + b.WithKind("ClusterTestType") + b.WithAPIVersion("example.crd.code-generator.k8s.io/v1") + return b +} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithKind(value string) *ClusterTestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithAPIVersion(value string) *ClusterTestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithName(value string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithGenerateName(value string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithNamespace(value string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithUID(value types.UID) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithResourceVersion(value string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithGeneration(value int64) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithCreationTimestamp(value apismetav1.Time) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithDeletionTimestamp(value apismetav1.Time) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *ClusterTestTypeApplyConfiguration) WithLabels(entries map[string]string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *ClusterTestTypeApplyConfiguration) WithAnnotations(entries map[string]string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *ClusterTestTypeApplyConfiguration) WithOwnerReferences(values ...*metav1.OwnerReferenceApplyConfiguration) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *ClusterTestTypeApplyConfiguration) WithFinalizers(values ...string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *ClusterTestTypeApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &metav1.ObjectMetaApplyConfiguration{} + } +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithStatus(value *ClusterTestTypeStatusApplyConfiguration) *ClusterTestTypeApplyConfiguration { + b.Status = value + return b +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *ClusterTestTypeApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} diff --git a/code-generator/examples/crd/applyconfiguration/example/v1/clustertesttypestatus.go b/code-generator/examples/crd/applyconfiguration/example/v1/clustertesttypestatus.go new file mode 100644 index 000000000..c2ccfa581 --- /dev/null +++ b/code-generator/examples/crd/applyconfiguration/example/v1/clustertesttypestatus.go @@ -0,0 +1,39 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// ClusterTestTypeStatusApplyConfiguration represents a declarative configuration of the ClusterTestTypeStatus type for use +// with apply. +type ClusterTestTypeStatusApplyConfiguration struct { + Blah *string `json:"blah,omitempty"` +} + +// ClusterTestTypeStatusApplyConfiguration constructs a declarative configuration of the ClusterTestTypeStatus type for use with +// apply. +func ClusterTestTypeStatus() *ClusterTestTypeStatusApplyConfiguration { + return &ClusterTestTypeStatusApplyConfiguration{} +} + +// WithBlah sets the Blah field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Blah field is set to the value of the last call. +func (b *ClusterTestTypeStatusApplyConfiguration) WithBlah(value string) *ClusterTestTypeStatusApplyConfiguration { + b.Blah = &value + return b +} diff --git a/code-generator/examples/crd/applyconfiguration/example/v1/testtype.go b/code-generator/examples/crd/applyconfiguration/example/v1/testtype.go new file mode 100644 index 000000000..49fdd2a66 --- /dev/null +++ b/code-generator/examples/crd/applyconfiguration/example/v1/testtype.go @@ -0,0 +1,216 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +import ( + apismetav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + metav1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// TestTypeApplyConfiguration represents a declarative configuration of the TestType type for use +// with apply. +type TestTypeApplyConfiguration struct { + metav1.TypeMetaApplyConfiguration `json:",inline"` + *metav1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Status *TestTypeStatusApplyConfiguration `json:"status,omitempty"` +} + +// TestType constructs a declarative configuration of the TestType type for use with +// apply. +func TestType(name, namespace string) *TestTypeApplyConfiguration { + b := &TestTypeApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("TestType") + b.WithAPIVersion("example.crd.code-generator.k8s.io/v1") + return b +} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithKind(value string) *TestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithAPIVersion(value string) *TestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithName(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithGenerateName(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithNamespace(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithUID(value types.UID) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithResourceVersion(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithGeneration(value int64) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithCreationTimestamp(value apismetav1.Time) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithDeletionTimestamp(value apismetav1.Time) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *TestTypeApplyConfiguration) WithLabels(entries map[string]string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *TestTypeApplyConfiguration) WithAnnotations(entries map[string]string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *TestTypeApplyConfiguration) WithOwnerReferences(values ...*metav1.OwnerReferenceApplyConfiguration) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *TestTypeApplyConfiguration) WithFinalizers(values ...string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *TestTypeApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &metav1.ObjectMetaApplyConfiguration{} + } +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithStatus(value *TestTypeStatusApplyConfiguration) *TestTypeApplyConfiguration { + b.Status = value + return b +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *TestTypeApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} diff --git a/code-generator/examples/crd/applyconfiguration/example/v1/testtypestatus.go b/code-generator/examples/crd/applyconfiguration/example/v1/testtypestatus.go new file mode 100644 index 000000000..246b2ee18 --- /dev/null +++ b/code-generator/examples/crd/applyconfiguration/example/v1/testtypestatus.go @@ -0,0 +1,39 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// TestTypeStatusApplyConfiguration represents a declarative configuration of the TestTypeStatus type for use +// with apply. +type TestTypeStatusApplyConfiguration struct { + Blah *string `json:"blah,omitempty"` +} + +// TestTypeStatusApplyConfiguration constructs a declarative configuration of the TestTypeStatus type for use with +// apply. +func TestTypeStatus() *TestTypeStatusApplyConfiguration { + return &TestTypeStatusApplyConfiguration{} +} + +// WithBlah sets the Blah field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Blah field is set to the value of the last call. +func (b *TestTypeStatusApplyConfiguration) WithBlah(value string) *TestTypeStatusApplyConfiguration { + b.Blah = &value + return b +} diff --git a/code-generator/examples/crd/applyconfiguration/example2/v1/testtype.go b/code-generator/examples/crd/applyconfiguration/example2/v1/testtype.go new file mode 100644 index 000000000..9ece7994d --- /dev/null +++ b/code-generator/examples/crd/applyconfiguration/example2/v1/testtype.go @@ -0,0 +1,216 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +import ( + apismetav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + metav1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// TestTypeApplyConfiguration represents a declarative configuration of the TestType type for use +// with apply. +type TestTypeApplyConfiguration struct { + metav1.TypeMetaApplyConfiguration `json:",inline"` + *metav1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Status *TestTypeStatusApplyConfiguration `json:"status,omitempty"` +} + +// TestType constructs a declarative configuration of the TestType type for use with +// apply. +func TestType(name, namespace string) *TestTypeApplyConfiguration { + b := &TestTypeApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("TestType") + b.WithAPIVersion("example.test.crd.code-generator.k8s.io/v1") + return b +} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithKind(value string) *TestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithAPIVersion(value string) *TestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithName(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithGenerateName(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithNamespace(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithUID(value types.UID) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithResourceVersion(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithGeneration(value int64) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithCreationTimestamp(value apismetav1.Time) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithDeletionTimestamp(value apismetav1.Time) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *TestTypeApplyConfiguration) WithLabels(entries map[string]string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *TestTypeApplyConfiguration) WithAnnotations(entries map[string]string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *TestTypeApplyConfiguration) WithOwnerReferences(values ...*metav1.OwnerReferenceApplyConfiguration) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *TestTypeApplyConfiguration) WithFinalizers(values ...string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *TestTypeApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &metav1.ObjectMetaApplyConfiguration{} + } +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithStatus(value *TestTypeStatusApplyConfiguration) *TestTypeApplyConfiguration { + b.Status = value + return b +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *TestTypeApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} diff --git a/code-generator/examples/crd/applyconfiguration/example2/v1/testtypestatus.go b/code-generator/examples/crd/applyconfiguration/example2/v1/testtypestatus.go new file mode 100644 index 000000000..246b2ee18 --- /dev/null +++ b/code-generator/examples/crd/applyconfiguration/example2/v1/testtypestatus.go @@ -0,0 +1,39 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// TestTypeStatusApplyConfiguration represents a declarative configuration of the TestTypeStatus type for use +// with apply. +type TestTypeStatusApplyConfiguration struct { + Blah *string `json:"blah,omitempty"` +} + +// TestTypeStatusApplyConfiguration constructs a declarative configuration of the TestTypeStatus type for use with +// apply. +func TestTypeStatus() *TestTypeStatusApplyConfiguration { + return &TestTypeStatusApplyConfiguration{} +} + +// WithBlah sets the Blah field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Blah field is set to the value of the last call. +func (b *TestTypeStatusApplyConfiguration) WithBlah(value string) *TestTypeStatusApplyConfiguration { + b.Blah = &value + return b +} diff --git a/code-generator/examples/crd/applyconfiguration/internal/internal.go b/code-generator/examples/crd/applyconfiguration/internal/internal.go new file mode 100644 index 000000000..1064e227e --- /dev/null +++ b/code-generator/examples/crd/applyconfiguration/internal/internal.go @@ -0,0 +1,62 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package internal + +import ( + fmt "fmt" + sync "sync" + + typed "sigs.k8s.io/structured-merge-diff/v4/typed" +) + +func Parser() *typed.Parser { + parserOnce.Do(func() { + var err error + parser, err = typed.NewParser(schemaYAML) + if err != nil { + panic(fmt.Sprintf("Failed to parse schema: %v", err)) + } + }) + return parser +} + +var parserOnce sync.Once +var parser *typed.Parser +var schemaYAML = typed.YAMLObject(`types: +- name: __untyped_atomic_ + scalar: untyped + list: + elementType: + namedType: __untyped_atomic_ + elementRelationship: atomic + map: + elementType: + namedType: __untyped_atomic_ + elementRelationship: atomic +- name: __untyped_deduced_ + scalar: untyped + list: + elementType: + namedType: __untyped_atomic_ + elementRelationship: atomic + map: + elementType: + namedType: __untyped_deduced_ + elementRelationship: separable +`) diff --git a/code-generator/examples/crd/applyconfiguration/utils.go b/code-generator/examples/crd/applyconfiguration/utils.go new file mode 100644 index 000000000..6ee2582b4 --- /dev/null +++ b/code-generator/examples/crd/applyconfiguration/utils.go @@ -0,0 +1,68 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package applyconfiguration + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/crd/apis/conflicting/v1" + examplev1 "k8s.io/code-generator/examples/crd/apis/example/v1" + example2v1 "k8s.io/code-generator/examples/crd/apis/example2/v1" + conflictingv1 "k8s.io/code-generator/examples/crd/applyconfiguration/conflicting/v1" + applyconfigurationexamplev1 "k8s.io/code-generator/examples/crd/applyconfiguration/example/v1" + applyconfigurationexample2v1 "k8s.io/code-generator/examples/crd/applyconfiguration/example2/v1" + internal "k8s.io/code-generator/examples/crd/applyconfiguration/internal" +) + +// ForKind returns an apply configuration type for the given GroupVersionKind, or nil if no +// apply configuration type exists for the given GroupVersionKind. +func ForKind(kind schema.GroupVersionKind) interface{} { + switch kind { + // Group=conflicting.test.crd.code-generator.k8s.io, Version=v1 + case v1.SchemeGroupVersion.WithKind("TestEmbeddedType"): + return &conflictingv1.TestEmbeddedTypeApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("TestType"): + return &conflictingv1.TestTypeApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("TestTypeStatus"): + return &conflictingv1.TestTypeStatusApplyConfiguration{} + + // Group=example.crd.code-generator.k8s.io, Version=v1 + case examplev1.SchemeGroupVersion.WithKind("ClusterTestType"): + return &applyconfigurationexamplev1.ClusterTestTypeApplyConfiguration{} + case examplev1.SchemeGroupVersion.WithKind("ClusterTestTypeStatus"): + return &applyconfigurationexamplev1.ClusterTestTypeStatusApplyConfiguration{} + case examplev1.SchemeGroupVersion.WithKind("TestType"): + return &applyconfigurationexamplev1.TestTypeApplyConfiguration{} + case examplev1.SchemeGroupVersion.WithKind("TestTypeStatus"): + return &applyconfigurationexamplev1.TestTypeStatusApplyConfiguration{} + + // Group=example.test.crd.code-generator.k8s.io, Version=v1 + case example2v1.SchemeGroupVersion.WithKind("TestType"): + return &applyconfigurationexample2v1.TestTypeApplyConfiguration{} + case example2v1.SchemeGroupVersion.WithKind("TestTypeStatus"): + return &applyconfigurationexample2v1.TestTypeStatusApplyConfiguration{} + + } + return nil +} + +func NewTypeConverter(scheme *runtime.Scheme) *testing.TypeConverter { + return &testing.TypeConverter{Scheme: scheme, TypeResolver: internal.Parser()} +} diff --git a/code-generator/examples/crd/clientset/versioned/clientset.go b/code-generator/examples/crd/clientset/versioned/clientset.go new file mode 100644 index 000000000..dea1369fb --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/clientset.go @@ -0,0 +1,146 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package versioned + +import ( + fmt "fmt" + http "net/http" + + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" + conflictingexamplev1 "k8s.io/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1" + examplev1 "k8s.io/code-generator/examples/crd/clientset/versioned/typed/example/v1" + secondexamplev1 "k8s.io/code-generator/examples/crd/clientset/versioned/typed/example2/v1" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + ConflictingExampleV1() conflictingexamplev1.ConflictingExampleV1Interface + ExampleV1() examplev1.ExampleV1Interface + SecondExampleV1() secondexamplev1.SecondExampleV1Interface +} + +// Clientset contains the clients for groups. +type Clientset struct { + *discovery.DiscoveryClient + conflictingExampleV1 *conflictingexamplev1.ConflictingExampleV1Client + exampleV1 *examplev1.ExampleV1Client + secondExampleV1 *secondexamplev1.SecondExampleV1Client +} + +// ConflictingExampleV1 retrieves the ConflictingExampleV1Client +func (c *Clientset) ConflictingExampleV1() conflictingexamplev1.ConflictingExampleV1Interface { + return c.conflictingExampleV1 +} + +// ExampleV1 retrieves the ExampleV1Client +func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { + return c.exampleV1 +} + +// SecondExampleV1 retrieves the SecondExampleV1Client +func (c *Clientset) SecondExampleV1() secondexamplev1.SecondExampleV1Interface { + return c.secondExampleV1 +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfig will generate a rate-limiter in configShallowCopy. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + + if configShallowCopy.UserAgent == "" { + configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent() + } + + // share the transport between all clients + httpClient, err := rest.HTTPClientFor(&configShallowCopy) + if err != nil { + return nil, err + } + + return NewForConfigAndClient(&configShallowCopy, httpClient) +} + +// NewForConfigAndClient creates a new Clientset for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfigAndClient will generate a rate-limiter in configShallowCopy. +func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + if configShallowCopy.Burst <= 0 { + return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") + } + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + + var cs Clientset + var err error + cs.conflictingExampleV1, err = conflictingexamplev1.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + cs.exampleV1, err = examplev1.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + cs.secondExampleV1, err = secondexamplev1.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + cs, err := NewForConfig(c) + if err != nil { + panic(err) + } + return cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.conflictingExampleV1 = conflictingexamplev1.New(c) + cs.exampleV1 = examplev1.New(c) + cs.secondExampleV1 = secondexamplev1.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/code-generator/examples/crd/clientset/versioned/fake/clientset_generated.go b/code-generator/examples/crd/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 000000000..a1d5fb472 --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/fake/clientset_generated.go @@ -0,0 +1,136 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" + applyconfiguration "k8s.io/code-generator/examples/crd/applyconfiguration" + clientset "k8s.io/code-generator/examples/crd/clientset/versioned" + conflictingexamplev1 "k8s.io/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1" + fakeconflictingexamplev1 "k8s.io/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/fake" + examplev1 "k8s.io/code-generator/examples/crd/clientset/versioned/typed/example/v1" + fakeexamplev1 "k8s.io/code-generator/examples/crd/clientset/versioned/typed/example/v1/fake" + secondexamplev1 "k8s.io/code-generator/examples/crd/clientset/versioned/typed/example2/v1" + fakesecondexamplev1 "k8s.io/code-generator/examples/crd/clientset/versioned/typed/example2/v1/fake" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any field management, validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +// +// DEPRECATED: NewClientset replaces this with support for field management, which significantly improves +// server side apply testing. NewClientset is only available when apply configurations are generated (e.g. +// via --with-applyconfig). +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery + tracker testing.ObjectTracker +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +func (c *Clientset) Tracker() testing.ObjectTracker { + return c.tracker +} + +// NewClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewClientset(objects ...runtime.Object) *Clientset { + o := testing.NewFieldManagedObjectTracker( + scheme, + codecs.UniversalDecoder(), + applyconfiguration.NewTypeConverter(scheme), + ) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +var ( + _ clientset.Interface = &Clientset{} + _ testing.FakeClient = &Clientset{} +) + +// ConflictingExampleV1 retrieves the ConflictingExampleV1Client +func (c *Clientset) ConflictingExampleV1() conflictingexamplev1.ConflictingExampleV1Interface { + return &fakeconflictingexamplev1.FakeConflictingExampleV1{Fake: &c.Fake} +} + +// ExampleV1 retrieves the ExampleV1Client +func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { + return &fakeexamplev1.FakeExampleV1{Fake: &c.Fake} +} + +// SecondExampleV1 retrieves the SecondExampleV1Client +func (c *Clientset) SecondExampleV1() secondexamplev1.SecondExampleV1Interface { + return &fakesecondexamplev1.FakeSecondExampleV1{Fake: &c.Fake} +} diff --git a/code-generator/examples/crd/clientset/versioned/fake/doc.go b/code-generator/examples/crd/clientset/versioned/fake/doc.go new file mode 100644 index 000000000..9b99e7167 --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/code-generator/examples/crd/clientset/versioned/fake/register.go b/code-generator/examples/crd/clientset/versioned/fake/register.go new file mode 100644 index 000000000..4cb0b57b9 --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/fake/register.go @@ -0,0 +1,60 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + conflictingexamplev1 "k8s.io/code-generator/examples/crd/apis/conflicting/v1" + examplev1 "k8s.io/code-generator/examples/crd/apis/example/v1" + secondexamplev1 "k8s.io/code-generator/examples/crd/apis/example2/v1" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) + +var localSchemeBuilder = runtime.SchemeBuilder{ + conflictingexamplev1.AddToScheme, + examplev1.AddToScheme, + secondexamplev1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) +} diff --git a/code-generator/examples/crd/clientset/versioned/scheme/doc.go b/code-generator/examples/crd/clientset/versioned/scheme/doc.go new file mode 100644 index 000000000..7dc375616 --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/scheme/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/code-generator/examples/crd/clientset/versioned/scheme/register.go b/code-generator/examples/crd/clientset/versioned/scheme/register.go new file mode 100644 index 000000000..146825e2d --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/scheme/register.go @@ -0,0 +1,60 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + conflictingexamplev1 "k8s.io/code-generator/examples/crd/apis/conflicting/v1" + examplev1 "k8s.io/code-generator/examples/crd/apis/example/v1" + secondexamplev1 "k8s.io/code-generator/examples/crd/apis/example2/v1" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + conflictingexamplev1.AddToScheme, + examplev1.AddToScheme, + secondexamplev1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(Scheme)) +} diff --git a/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/conflicting_client.go b/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/conflicting_client.go new file mode 100644 index 000000000..208d77637 --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/conflicting_client.go @@ -0,0 +1,107 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + http "net/http" + + rest "k8s.io/client-go/rest" + conflictingv1 "k8s.io/code-generator/examples/crd/apis/conflicting/v1" + scheme "k8s.io/code-generator/examples/crd/clientset/versioned/scheme" +) + +type ConflictingExampleV1Interface interface { + RESTClient() rest.Interface + TestTypesGetter +} + +// ConflictingExampleV1Client is used to interact with features provided by the conflicting.test.crd.code-generator.k8s.io group. +type ConflictingExampleV1Client struct { + restClient rest.Interface +} + +func (c *ConflictingExampleV1Client) TestTypes(namespace string) TestTypeInterface { + return newTestTypes(c, namespace) +} + +// NewForConfig creates a new ConflictingExampleV1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*ConflictingExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new ConflictingExampleV1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*ConflictingExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &ConflictingExampleV1Client{client}, nil +} + +// NewForConfigOrDie creates a new ConflictingExampleV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ConflictingExampleV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ConflictingExampleV1Client for the given RESTClient. +func New(c rest.Interface) *ConflictingExampleV1Client { + return &ConflictingExampleV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := conflictingv1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *ConflictingExampleV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/doc.go b/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/doc.go new file mode 100644 index 000000000..3af5d054f --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/fake/doc.go b/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/fake/fake_conflicting_client.go b/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/fake/fake_conflicting_client.go new file mode 100644 index 000000000..f3011126b --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/fake/fake_conflicting_client.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1" +) + +type FakeConflictingExampleV1 struct { + *testing.Fake +} + +func (c *FakeConflictingExampleV1) TestTypes(namespace string) v1.TestTypeInterface { + return &FakeTestTypes{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeConflictingExampleV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/fake/fake_testtype.go b/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/fake/fake_testtype.go new file mode 100644 index 000000000..79cb4573f --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/fake/fake_testtype.go @@ -0,0 +1,197 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + json "encoding/json" + fmt "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/crd/apis/conflicting/v1" + conflictingv1 "k8s.io/code-generator/examples/crd/applyconfiguration/conflicting/v1" +) + +// FakeTestTypes implements TestTypeInterface +type FakeTestTypes struct { + Fake *FakeConflictingExampleV1 + ns string +} + +var testtypesResource = v1.SchemeGroupVersion.WithResource("testtypes") + +var testtypesKind = v1.SchemeGroupVersion.WithKind("TestType") + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewGetActionWithOptions(testtypesResource, c.ns, name, options), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *FakeTestTypes) List(ctx context.Context, opts metav1.ListOptions) (result *v1.TestTypeList, err error) { + emptyResult := &v1.TestTypeList{} + obj, err := c.Fake. + Invokes(testing.NewListActionWithOptions(testtypesResource, testtypesKind, c.ns, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1.TestTypeList{ListMeta: obj.(*v1.TestTypeList).ListMeta} + for _, item := range obj.(*v1.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchActionWithOptions(testtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Create(ctx context.Context, testType *v1.TestType, opts metav1.CreateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewCreateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Update(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTestTypes) UpdateStatus(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceActionWithOptions(testtypesResource, "status", c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *FakeTestTypes) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(testtypesResource, c.ns, name, opts), &v1.TestType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTestTypes) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + action := testing.NewDeleteCollectionActionWithOptions(testtypesResource, c.ns, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1.TestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched testType. +func (c *FakeTestTypes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied testType. +func (c *FakeTestTypes) Apply(ctx context.Context, testType *conflictingv1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.TestType, err error) { + if testType == nil { + return nil, fmt.Errorf("testType provided to Apply must not be nil") + } + data, err := json.Marshal(testType) + if err != nil { + return nil, err + } + name := testType.Name + if name == nil { + return nil, fmt.Errorf("testType.Name must be provided to Apply") + } + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeTestTypes) ApplyStatus(ctx context.Context, testType *conflictingv1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.TestType, err error) { + if testType == nil { + return nil, fmt.Errorf("testType provided to Apply must not be nil") + } + data, err := json.Marshal(testType) + if err != nil { + return nil, err + } + name := testType.Name + if name == nil { + return nil, fmt.Errorf("testType.Name must be provided to Apply") + } + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions(), "status"), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} diff --git a/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/generated_expansion.go b/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/generated_expansion.go new file mode 100644 index 000000000..d513810d0 --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/generated_expansion.go @@ -0,0 +1,21 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type TestTypeExpansion interface{} diff --git a/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/testtype.go b/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/testtype.go new file mode 100644 index 000000000..5d089755e --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/conflicting/v1/testtype.go @@ -0,0 +1,73 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + conflictingv1 "k8s.io/code-generator/examples/crd/apis/conflicting/v1" + applyconfigurationconflictingv1 "k8s.io/code-generator/examples/crd/applyconfiguration/conflicting/v1" + scheme "k8s.io/code-generator/examples/crd/clientset/versioned/scheme" +) + +// TestTypesGetter has a method to return a TestTypeInterface. +// A group's client should implement this interface. +type TestTypesGetter interface { + TestTypes(namespace string) TestTypeInterface +} + +// TestTypeInterface has methods to work with TestType resources. +type TestTypeInterface interface { + Create(ctx context.Context, testType *conflictingv1.TestType, opts metav1.CreateOptions) (*conflictingv1.TestType, error) + Update(ctx context.Context, testType *conflictingv1.TestType, opts metav1.UpdateOptions) (*conflictingv1.TestType, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, testType *conflictingv1.TestType, opts metav1.UpdateOptions) (*conflictingv1.TestType, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*conflictingv1.TestType, error) + List(ctx context.Context, opts metav1.ListOptions) (*conflictingv1.TestTypeList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *conflictingv1.TestType, err error) + Apply(ctx context.Context, testType *applyconfigurationconflictingv1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *conflictingv1.TestType, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, testType *applyconfigurationconflictingv1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *conflictingv1.TestType, err error) + TestTypeExpansion +} + +// testTypes implements TestTypeInterface +type testTypes struct { + *gentype.ClientWithListAndApply[*conflictingv1.TestType, *conflictingv1.TestTypeList, *applyconfigurationconflictingv1.TestTypeApplyConfiguration] +} + +// newTestTypes returns a TestTypes +func newTestTypes(c *ConflictingExampleV1Client, namespace string) *testTypes { + return &testTypes{ + gentype.NewClientWithListAndApply[*conflictingv1.TestType, *conflictingv1.TestTypeList, *applyconfigurationconflictingv1.TestTypeApplyConfiguration]( + "testtypes", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *conflictingv1.TestType { return &conflictingv1.TestType{} }, + func() *conflictingv1.TestTypeList { return &conflictingv1.TestTypeList{} }), + } +} diff --git a/code-generator/examples/crd/clientset/versioned/typed/example/v1/clustertesttype.go b/code-generator/examples/crd/clientset/versioned/typed/example/v1/clustertesttype.go new file mode 100644 index 000000000..6178e0a66 --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/example/v1/clustertesttype.go @@ -0,0 +1,104 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + + autoscalingv1 "k8s.io/api/autoscaling/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + examplev1 "k8s.io/code-generator/examples/crd/apis/example/v1" + applyconfigurationexamplev1 "k8s.io/code-generator/examples/crd/applyconfiguration/example/v1" + scheme "k8s.io/code-generator/examples/crd/clientset/versioned/scheme" +) + +// ClusterTestTypesGetter has a method to return a ClusterTestTypeInterface. +// A group's client should implement this interface. +type ClusterTestTypesGetter interface { + ClusterTestTypes() ClusterTestTypeInterface +} + +// ClusterTestTypeInterface has methods to work with ClusterTestType resources. +type ClusterTestTypeInterface interface { + Create(ctx context.Context, clusterTestType *examplev1.ClusterTestType, opts metav1.CreateOptions) (*examplev1.ClusterTestType, error) + Update(ctx context.Context, clusterTestType *examplev1.ClusterTestType, opts metav1.UpdateOptions) (*examplev1.ClusterTestType, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, clusterTestType *examplev1.ClusterTestType, opts metav1.UpdateOptions) (*examplev1.ClusterTestType, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*examplev1.ClusterTestType, error) + List(ctx context.Context, opts metav1.ListOptions) (*examplev1.ClusterTestTypeList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *examplev1.ClusterTestType, err error) + Apply(ctx context.Context, clusterTestType *applyconfigurationexamplev1.ClusterTestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *examplev1.ClusterTestType, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, clusterTestType *applyconfigurationexamplev1.ClusterTestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *examplev1.ClusterTestType, err error) + GetScale(ctx context.Context, clusterTestTypeName string, options metav1.GetOptions) (*autoscalingv1.Scale, error) + UpdateScale(ctx context.Context, clusterTestTypeName string, scale *autoscalingv1.Scale, opts metav1.UpdateOptions) (*autoscalingv1.Scale, error) + + ClusterTestTypeExpansion +} + +// clusterTestTypes implements ClusterTestTypeInterface +type clusterTestTypes struct { + *gentype.ClientWithListAndApply[*examplev1.ClusterTestType, *examplev1.ClusterTestTypeList, *applyconfigurationexamplev1.ClusterTestTypeApplyConfiguration] +} + +// newClusterTestTypes returns a ClusterTestTypes +func newClusterTestTypes(c *ExampleV1Client) *clusterTestTypes { + return &clusterTestTypes{ + gentype.NewClientWithListAndApply[*examplev1.ClusterTestType, *examplev1.ClusterTestTypeList, *applyconfigurationexamplev1.ClusterTestTypeApplyConfiguration]( + "clustertesttypes", + c.RESTClient(), + scheme.ParameterCodec, + "", + func() *examplev1.ClusterTestType { return &examplev1.ClusterTestType{} }, + func() *examplev1.ClusterTestTypeList { return &examplev1.ClusterTestTypeList{} }), + } +} + +// GetScale takes name of the clusterTestType, and returns the corresponding autoscalingv1.Scale object, and an error if there is any. +func (c *clusterTestTypes) GetScale(ctx context.Context, clusterTestTypeName string, options metav1.GetOptions) (result *autoscalingv1.Scale, err error) { + result = &autoscalingv1.Scale{} + err = c.GetClient().Get(). + Resource("clustertesttypes"). + Name(clusterTestTypeName). + SubResource("scale"). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *clusterTestTypes) UpdateScale(ctx context.Context, clusterTestTypeName string, scale *autoscalingv1.Scale, opts metav1.UpdateOptions) (result *autoscalingv1.Scale, err error) { + result = &autoscalingv1.Scale{} + err = c.GetClient().Put(). + Resource("clustertesttypes"). + Name(clusterTestTypeName). + SubResource("scale"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(scale). + Do(ctx). + Into(result) + return +} diff --git a/code-generator/examples/crd/clientset/versioned/typed/example/v1/doc.go b/code-generator/examples/crd/clientset/versioned/typed/example/v1/doc.go new file mode 100644 index 000000000..3af5d054f --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/example/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/code-generator/examples/crd/clientset/versioned/typed/example/v1/example_client.go b/code-generator/examples/crd/clientset/versioned/typed/example/v1/example_client.go new file mode 100644 index 000000000..98c052a01 --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/example/v1/example_client.go @@ -0,0 +1,112 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + http "net/http" + + rest "k8s.io/client-go/rest" + examplev1 "k8s.io/code-generator/examples/crd/apis/example/v1" + scheme "k8s.io/code-generator/examples/crd/clientset/versioned/scheme" +) + +type ExampleV1Interface interface { + RESTClient() rest.Interface + ClusterTestTypesGetter + TestTypesGetter +} + +// ExampleV1Client is used to interact with features provided by the example.crd.code-generator.k8s.io group. +type ExampleV1Client struct { + restClient rest.Interface +} + +func (c *ExampleV1Client) ClusterTestTypes() ClusterTestTypeInterface { + return newClusterTestTypes(c) +} + +func (c *ExampleV1Client) TestTypes(namespace string) TestTypeInterface { + return newTestTypes(c, namespace) +} + +// NewForConfig creates a new ExampleV1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*ExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new ExampleV1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*ExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &ExampleV1Client{client}, nil +} + +// NewForConfigOrDie creates a new ExampleV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ExampleV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ExampleV1Client for the given RESTClient. +func New(c rest.Interface) *ExampleV1Client { + return &ExampleV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := examplev1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *ExampleV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/code-generator/examples/crd/clientset/versioned/typed/example/v1/fake/doc.go b/code-generator/examples/crd/clientset/versioned/typed/example/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/example/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/code-generator/examples/crd/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go b/code-generator/examples/crd/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go new file mode 100644 index 000000000..c512d065f --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/example/v1/fake/fake_clustertesttype.go @@ -0,0 +1,209 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + json "encoding/json" + fmt "fmt" + + autoscalingv1 "k8s.io/api/autoscaling/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/crd/apis/example/v1" + examplev1 "k8s.io/code-generator/examples/crd/applyconfiguration/example/v1" +) + +// FakeClusterTestTypes implements ClusterTestTypeInterface +type FakeClusterTestTypes struct { + Fake *FakeExampleV1 +} + +var clustertesttypesResource = v1.SchemeGroupVersion.WithResource("clustertesttypes") + +var clustertesttypesKind = v1.SchemeGroupVersion.WithKind("ClusterTestType") + +// Get takes name of the clusterTestType, and returns the corresponding clusterTestType object, and an error if there is any. +func (c *FakeClusterTestTypes) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootGetActionWithOptions(clustertesttypesResource, name, options), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// List takes label and field selectors, and returns the list of ClusterTestTypes that match those selectors. +func (c *FakeClusterTestTypes) List(ctx context.Context, opts metav1.ListOptions) (result *v1.ClusterTestTypeList, err error) { + emptyResult := &v1.ClusterTestTypeList{} + obj, err := c.Fake. + Invokes(testing.NewRootListActionWithOptions(clustertesttypesResource, clustertesttypesKind, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1.ClusterTestTypeList{ListMeta: obj.(*v1.ClusterTestTypeList).ListMeta} + for _, item := range obj.(*v1.ClusterTestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested clusterTestTypes. +func (c *FakeClusterTestTypes) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchActionWithOptions(clustertesttypesResource, opts)) +} + +// Create takes the representation of a clusterTestType and creates it. Returns the server's representation of the clusterTestType, and an error, if there is any. +func (c *FakeClusterTestTypes) Create(ctx context.Context, clusterTestType *v1.ClusterTestType, opts metav1.CreateOptions) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootCreateActionWithOptions(clustertesttypesResource, clusterTestType, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// Update takes the representation of a clusterTestType and updates it. Returns the server's representation of the clusterTestType, and an error, if there is any. +func (c *FakeClusterTestTypes) Update(ctx context.Context, clusterTestType *v1.ClusterTestType, opts metav1.UpdateOptions) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootUpdateActionWithOptions(clustertesttypesResource, clusterTestType, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeClusterTestTypes) UpdateStatus(ctx context.Context, clusterTestType *v1.ClusterTestType, opts metav1.UpdateOptions) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceActionWithOptions(clustertesttypesResource, "status", clusterTestType, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// Delete takes name of the clusterTestType and deletes it. Returns an error if one occurs. +func (c *FakeClusterTestTypes) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(clustertesttypesResource, name, opts), &v1.ClusterTestType{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeClusterTestTypes) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + action := testing.NewRootDeleteCollectionActionWithOptions(clustertesttypesResource, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1.ClusterTestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched clusterTestType. +func (c *FakeClusterTestTypes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clustertesttypesResource, name, pt, data, opts, subresources...), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied clusterTestType. +func (c *FakeClusterTestTypes) Apply(ctx context.Context, clusterTestType *examplev1.ClusterTestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.ClusterTestType, err error) { + if clusterTestType == nil { + return nil, fmt.Errorf("clusterTestType provided to Apply must not be nil") + } + data, err := json.Marshal(clusterTestType) + if err != nil { + return nil, err + } + name := clusterTestType.Name + if name == nil { + return nil, fmt.Errorf("clusterTestType.Name must be provided to Apply") + } + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clustertesttypesResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeClusterTestTypes) ApplyStatus(ctx context.Context, clusterTestType *examplev1.ClusterTestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.ClusterTestType, err error) { + if clusterTestType == nil { + return nil, fmt.Errorf("clusterTestType provided to Apply must not be nil") + } + data, err := json.Marshal(clusterTestType) + if err != nil { + return nil, err + } + name := clusterTestType.Name + if name == nil { + return nil, fmt.Errorf("clusterTestType.Name must be provided to Apply") + } + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clustertesttypesResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions(), "status"), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// GetScale takes name of the clusterTestType, and returns the corresponding scale object, and an error if there is any. +func (c *FakeClusterTestTypes) GetScale(ctx context.Context, clusterTestTypeName string, options metav1.GetOptions) (result *autoscalingv1.Scale, err error) { + emptyResult := &autoscalingv1.Scale{} + obj, err := c.Fake. + Invokes(testing.NewRootGetSubresourceActionWithOptions(clustertesttypesResource, "scale", clusterTestTypeName, options), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*autoscalingv1.Scale), err +} + +// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *FakeClusterTestTypes) UpdateScale(ctx context.Context, clusterTestTypeName string, scale *autoscalingv1.Scale, opts metav1.UpdateOptions) (result *autoscalingv1.Scale, err error) { + emptyResult := &autoscalingv1.Scale{} + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceActionWithOptions(clustertesttypesResource, "scale", scale, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*autoscalingv1.Scale), err +} diff --git a/code-generator/examples/crd/clientset/versioned/typed/example/v1/fake/fake_example_client.go b/code-generator/examples/crd/clientset/versioned/typed/example/v1/fake/fake_example_client.go new file mode 100644 index 000000000..44bd7f810 --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/example/v1/fake/fake_example_client.go @@ -0,0 +1,44 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/crd/clientset/versioned/typed/example/v1" +) + +type FakeExampleV1 struct { + *testing.Fake +} + +func (c *FakeExampleV1) ClusterTestTypes() v1.ClusterTestTypeInterface { + return &FakeClusterTestTypes{c} +} + +func (c *FakeExampleV1) TestTypes(namespace string) v1.TestTypeInterface { + return &FakeTestTypes{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeExampleV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/code-generator/examples/crd/clientset/versioned/typed/example/v1/fake/fake_testtype.go b/code-generator/examples/crd/clientset/versioned/typed/example/v1/fake/fake_testtype.go new file mode 100644 index 000000000..d96012adc --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/example/v1/fake/fake_testtype.go @@ -0,0 +1,209 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + json "encoding/json" + fmt "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/crd/apis/example/v1" + examplev1 "k8s.io/code-generator/examples/crd/applyconfiguration/example/v1" +) + +// FakeTestTypes implements TestTypeInterface +type FakeTestTypes struct { + Fake *FakeExampleV1 + ns string +} + +var testtypesResource = v1.SchemeGroupVersion.WithResource("testtypes") + +var testtypesKind = v1.SchemeGroupVersion.WithKind("TestType") + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewGetActionWithOptions(testtypesResource, c.ns, name, options), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *FakeTestTypes) List(ctx context.Context, opts metav1.ListOptions) (result *v1.TestTypeList, err error) { + emptyResult := &v1.TestTypeList{} + obj, err := c.Fake. + Invokes(testing.NewListActionWithOptions(testtypesResource, testtypesKind, c.ns, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1.TestTypeList{ListMeta: obj.(*v1.TestTypeList).ListMeta} + for _, item := range obj.(*v1.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchActionWithOptions(testtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Create(ctx context.Context, testType *v1.TestType, opts metav1.CreateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewCreateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Update(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTestTypes) UpdateStatus(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceActionWithOptions(testtypesResource, "status", c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *FakeTestTypes) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(testtypesResource, c.ns, name, opts), &v1.TestType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTestTypes) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + action := testing.NewDeleteCollectionActionWithOptions(testtypesResource, c.ns, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1.TestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched testType. +func (c *FakeTestTypes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied testType. +func (c *FakeTestTypes) Apply(ctx context.Context, testType *examplev1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.TestType, err error) { + if testType == nil { + return nil, fmt.Errorf("testType provided to Apply must not be nil") + } + data, err := json.Marshal(testType) + if err != nil { + return nil, err + } + name := testType.Name + if name == nil { + return nil, fmt.Errorf("testType.Name must be provided to Apply") + } + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeTestTypes) ApplyStatus(ctx context.Context, testType *examplev1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.TestType, err error) { + if testType == nil { + return nil, fmt.Errorf("testType provided to Apply must not be nil") + } + data, err := json.Marshal(testType) + if err != nil { + return nil, err + } + name := testType.Name + if name == nil { + return nil, fmt.Errorf("testType.Name must be provided to Apply") + } + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions(), "status"), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// GetClusterTestType takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) GetClusterTestType(ctx context.Context, name string, options metav1.GetOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewGetActionWithOptions(testtypesResource, c.ns, name, options), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} diff --git a/code-generator/examples/crd/clientset/versioned/typed/example/v1/generated_expansion.go b/code-generator/examples/crd/clientset/versioned/typed/example/v1/generated_expansion.go new file mode 100644 index 000000000..3059734a9 --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/example/v1/generated_expansion.go @@ -0,0 +1,23 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type ClusterTestTypeExpansion interface{} + +type TestTypeExpansion interface{} diff --git a/code-generator/examples/crd/clientset/versioned/typed/example/v1/testtype.go b/code-generator/examples/crd/clientset/versioned/typed/example/v1/testtype.go new file mode 100644 index 000000000..721b8cd9e --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/example/v1/testtype.go @@ -0,0 +1,88 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + examplev1 "k8s.io/code-generator/examples/crd/apis/example/v1" + applyconfigurationexamplev1 "k8s.io/code-generator/examples/crd/applyconfiguration/example/v1" + scheme "k8s.io/code-generator/examples/crd/clientset/versioned/scheme" +) + +// TestTypesGetter has a method to return a TestTypeInterface. +// A group's client should implement this interface. +type TestTypesGetter interface { + TestTypes(namespace string) TestTypeInterface +} + +// TestTypeInterface has methods to work with TestType resources. +type TestTypeInterface interface { + Create(ctx context.Context, testType *examplev1.TestType, opts metav1.CreateOptions) (*examplev1.TestType, error) + Update(ctx context.Context, testType *examplev1.TestType, opts metav1.UpdateOptions) (*examplev1.TestType, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, testType *examplev1.TestType, opts metav1.UpdateOptions) (*examplev1.TestType, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*examplev1.TestType, error) + List(ctx context.Context, opts metav1.ListOptions) (*examplev1.TestTypeList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *examplev1.TestType, err error) + Apply(ctx context.Context, testType *applyconfigurationexamplev1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *examplev1.TestType, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, testType *applyconfigurationexamplev1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *examplev1.TestType, err error) + GetClusterTestType(ctx context.Context, name string, opts metav1.GetOptions) (*examplev1.TestType, error) + + TestTypeExpansion +} + +// testTypes implements TestTypeInterface +type testTypes struct { + *gentype.ClientWithListAndApply[*examplev1.TestType, *examplev1.TestTypeList, *applyconfigurationexamplev1.TestTypeApplyConfiguration] +} + +// newTestTypes returns a TestTypes +func newTestTypes(c *ExampleV1Client, namespace string) *testTypes { + return &testTypes{ + gentype.NewClientWithListAndApply[*examplev1.TestType, *examplev1.TestTypeList, *applyconfigurationexamplev1.TestTypeApplyConfiguration]( + "testtypes", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *examplev1.TestType { return &examplev1.TestType{} }, + func() *examplev1.TestTypeList { return &examplev1.TestTypeList{} }), + } +} + +// GetClusterTestType takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *testTypes) GetClusterTestType(ctx context.Context, name string, options metav1.GetOptions) (result *examplev1.TestType, err error) { + result = &examplev1.TestType{} + err = c.GetClient().Get(). + Namespace(c.GetNamespace()). + Resource("testtypes"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} diff --git a/code-generator/examples/crd/clientset/versioned/typed/example2/v1/doc.go b/code-generator/examples/crd/clientset/versioned/typed/example2/v1/doc.go new file mode 100644 index 000000000..3af5d054f --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/example2/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/code-generator/examples/crd/clientset/versioned/typed/example2/v1/example2_client.go b/code-generator/examples/crd/clientset/versioned/typed/example2/v1/example2_client.go new file mode 100644 index 000000000..8902a886f --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/example2/v1/example2_client.go @@ -0,0 +1,107 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + http "net/http" + + rest "k8s.io/client-go/rest" + example2v1 "k8s.io/code-generator/examples/crd/apis/example2/v1" + scheme "k8s.io/code-generator/examples/crd/clientset/versioned/scheme" +) + +type SecondExampleV1Interface interface { + RESTClient() rest.Interface + TestTypesGetter +} + +// SecondExampleV1Client is used to interact with features provided by the example.test.crd.code-generator.k8s.io group. +type SecondExampleV1Client struct { + restClient rest.Interface +} + +func (c *SecondExampleV1Client) TestTypes(namespace string) TestTypeInterface { + return newTestTypes(c, namespace) +} + +// NewForConfig creates a new SecondExampleV1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*SecondExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new SecondExampleV1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*SecondExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &SecondExampleV1Client{client}, nil +} + +// NewForConfigOrDie creates a new SecondExampleV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *SecondExampleV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new SecondExampleV1Client for the given RESTClient. +func New(c rest.Interface) *SecondExampleV1Client { + return &SecondExampleV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := example2v1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *SecondExampleV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/code-generator/examples/crd/clientset/versioned/typed/example2/v1/fake/doc.go b/code-generator/examples/crd/clientset/versioned/typed/example2/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/example2/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/code-generator/examples/crd/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go b/code-generator/examples/crd/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go new file mode 100644 index 000000000..c60f7ac9b --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/example2/v1/fake/fake_example2_client.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/crd/clientset/versioned/typed/example2/v1" +) + +type FakeSecondExampleV1 struct { + *testing.Fake +} + +func (c *FakeSecondExampleV1) TestTypes(namespace string) v1.TestTypeInterface { + return &FakeTestTypes{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeSecondExampleV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/code-generator/examples/crd/clientset/versioned/typed/example2/v1/fake/fake_testtype.go b/code-generator/examples/crd/clientset/versioned/typed/example2/v1/fake/fake_testtype.go new file mode 100644 index 000000000..349e732f5 --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/example2/v1/fake/fake_testtype.go @@ -0,0 +1,197 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + json "encoding/json" + fmt "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/crd/apis/example2/v1" + example2v1 "k8s.io/code-generator/examples/crd/applyconfiguration/example2/v1" +) + +// FakeTestTypes implements TestTypeInterface +type FakeTestTypes struct { + Fake *FakeSecondExampleV1 + ns string +} + +var testtypesResource = v1.SchemeGroupVersion.WithResource("testtypes") + +var testtypesKind = v1.SchemeGroupVersion.WithKind("TestType") + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewGetActionWithOptions(testtypesResource, c.ns, name, options), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *FakeTestTypes) List(ctx context.Context, opts metav1.ListOptions) (result *v1.TestTypeList, err error) { + emptyResult := &v1.TestTypeList{} + obj, err := c.Fake. + Invokes(testing.NewListActionWithOptions(testtypesResource, testtypesKind, c.ns, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1.TestTypeList{ListMeta: obj.(*v1.TestTypeList).ListMeta} + for _, item := range obj.(*v1.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchActionWithOptions(testtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Create(ctx context.Context, testType *v1.TestType, opts metav1.CreateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewCreateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Update(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTestTypes) UpdateStatus(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceActionWithOptions(testtypesResource, "status", c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *FakeTestTypes) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(testtypesResource, c.ns, name, opts), &v1.TestType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTestTypes) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + action := testing.NewDeleteCollectionActionWithOptions(testtypesResource, c.ns, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1.TestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched testType. +func (c *FakeTestTypes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied testType. +func (c *FakeTestTypes) Apply(ctx context.Context, testType *example2v1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.TestType, err error) { + if testType == nil { + return nil, fmt.Errorf("testType provided to Apply must not be nil") + } + data, err := json.Marshal(testType) + if err != nil { + return nil, err + } + name := testType.Name + if name == nil { + return nil, fmt.Errorf("testType.Name must be provided to Apply") + } + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeTestTypes) ApplyStatus(ctx context.Context, testType *example2v1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.TestType, err error) { + if testType == nil { + return nil, fmt.Errorf("testType provided to Apply must not be nil") + } + data, err := json.Marshal(testType) + if err != nil { + return nil, err + } + name := testType.Name + if name == nil { + return nil, fmt.Errorf("testType.Name must be provided to Apply") + } + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions(), "status"), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} diff --git a/code-generator/examples/crd/clientset/versioned/typed/example2/v1/generated_expansion.go b/code-generator/examples/crd/clientset/versioned/typed/example2/v1/generated_expansion.go new file mode 100644 index 000000000..d513810d0 --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/example2/v1/generated_expansion.go @@ -0,0 +1,21 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type TestTypeExpansion interface{} diff --git a/code-generator/examples/crd/clientset/versioned/typed/example2/v1/testtype.go b/code-generator/examples/crd/clientset/versioned/typed/example2/v1/testtype.go new file mode 100644 index 000000000..224af4caa --- /dev/null +++ b/code-generator/examples/crd/clientset/versioned/typed/example2/v1/testtype.go @@ -0,0 +1,73 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + example2v1 "k8s.io/code-generator/examples/crd/apis/example2/v1" + applyconfigurationexample2v1 "k8s.io/code-generator/examples/crd/applyconfiguration/example2/v1" + scheme "k8s.io/code-generator/examples/crd/clientset/versioned/scheme" +) + +// TestTypesGetter has a method to return a TestTypeInterface. +// A group's client should implement this interface. +type TestTypesGetter interface { + TestTypes(namespace string) TestTypeInterface +} + +// TestTypeInterface has methods to work with TestType resources. +type TestTypeInterface interface { + Create(ctx context.Context, testType *example2v1.TestType, opts metav1.CreateOptions) (*example2v1.TestType, error) + Update(ctx context.Context, testType *example2v1.TestType, opts metav1.UpdateOptions) (*example2v1.TestType, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, testType *example2v1.TestType, opts metav1.UpdateOptions) (*example2v1.TestType, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*example2v1.TestType, error) + List(ctx context.Context, opts metav1.ListOptions) (*example2v1.TestTypeList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *example2v1.TestType, err error) + Apply(ctx context.Context, testType *applyconfigurationexample2v1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *example2v1.TestType, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, testType *applyconfigurationexample2v1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *example2v1.TestType, err error) + TestTypeExpansion +} + +// testTypes implements TestTypeInterface +type testTypes struct { + *gentype.ClientWithListAndApply[*example2v1.TestType, *example2v1.TestTypeList, *applyconfigurationexample2v1.TestTypeApplyConfiguration] +} + +// newTestTypes returns a TestTypes +func newTestTypes(c *SecondExampleV1Client, namespace string) *testTypes { + return &testTypes{ + gentype.NewClientWithListAndApply[*example2v1.TestType, *example2v1.TestTypeList, *applyconfigurationexample2v1.TestTypeApplyConfiguration]( + "testtypes", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *example2v1.TestType { return &example2v1.TestType{} }, + func() *example2v1.TestTypeList { return &example2v1.TestTypeList{} }), + } +} diff --git a/code-generator/examples/crd/informers/externalversions/conflicting/interface.go b/code-generator/examples/crd/informers/externalversions/conflicting/interface.go new file mode 100644 index 000000000..9bd1fc317 --- /dev/null +++ b/code-generator/examples/crd/informers/externalversions/conflicting/interface.go @@ -0,0 +1,46 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package conflicting + +import ( + v1 "k8s.io/code-generator/examples/crd/informers/externalversions/conflicting/v1" + internalinterfaces "k8s.io/code-generator/examples/crd/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/generated/informers/externalversions/samplecontroller/v1alpha1/interface.go b/code-generator/examples/crd/informers/externalversions/conflicting/v1/interface.go similarity index 75% rename from pkg/generated/informers/externalversions/samplecontroller/v1alpha1/interface.go rename to code-generator/examples/crd/informers/externalversions/conflicting/v1/interface.go index 403b02760..d6c18a3a6 100644 --- a/pkg/generated/informers/externalversions/samplecontroller/v1alpha1/interface.go +++ b/code-generator/examples/crd/informers/externalversions/conflicting/v1/interface.go @@ -16,16 +16,16 @@ limitations under the License. // Code generated by informer-gen. DO NOT EDIT. -package v1alpha1 +package v1 import ( - internalinterfaces "k8s.io/sample-controller/pkg/generated/informers/externalversions/internalinterfaces" + internalinterfaces "k8s.io/code-generator/examples/crd/informers/externalversions/internalinterfaces" ) // Interface provides access to all the informers in this group version. type Interface interface { - // Foos returns a FooInformer. - Foos() FooInformer + // TestTypes returns a TestTypeInformer. + TestTypes() TestTypeInformer } type version struct { @@ -39,7 +39,7 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} } -// Foos returns a FooInformer. -func (v *version) Foos() FooInformer { - return &fooInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +// TestTypes returns a TestTypeInformer. +func (v *version) TestTypes() TestTypeInformer { + return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } diff --git a/code-generator/examples/crd/informers/externalversions/conflicting/v1/testtype.go b/code-generator/examples/crd/informers/externalversions/conflicting/v1/testtype.go new file mode 100644 index 000000000..b1406efd7 --- /dev/null +++ b/code-generator/examples/crd/informers/externalversions/conflicting/v1/testtype.go @@ -0,0 +1,90 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + apisconflictingv1 "k8s.io/code-generator/examples/crd/apis/conflicting/v1" + versioned "k8s.io/code-generator/examples/crd/clientset/versioned" + internalinterfaces "k8s.io/code-generator/examples/crd/informers/externalversions/internalinterfaces" + conflictingv1 "k8s.io/code-generator/examples/crd/listers/conflicting/v1" +) + +// TestTypeInformer provides access to a shared informer and lister for +// TestTypes. +type TestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() conflictingv1.TestTypeLister +} + +type testTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ConflictingExampleV1().TestTypes(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ConflictingExampleV1().TestTypes(namespace).Watch(context.TODO(), options) + }, + }, + &apisconflictingv1.TestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *testTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apisconflictingv1.TestType{}, f.defaultInformer) +} + +func (f *testTypeInformer) Lister() conflictingv1.TestTypeLister { + return conflictingv1.NewTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/code-generator/examples/crd/informers/externalversions/example/interface.go b/code-generator/examples/crd/informers/externalversions/example/interface.go new file mode 100644 index 000000000..6998eef4f --- /dev/null +++ b/code-generator/examples/crd/informers/externalversions/example/interface.go @@ -0,0 +1,46 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package example + +import ( + v1 "k8s.io/code-generator/examples/crd/informers/externalversions/example/v1" + internalinterfaces "k8s.io/code-generator/examples/crd/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/code-generator/examples/crd/informers/externalversions/example/v1/clustertesttype.go b/code-generator/examples/crd/informers/externalversions/example/v1/clustertesttype.go new file mode 100644 index 000000000..363487831 --- /dev/null +++ b/code-generator/examples/crd/informers/externalversions/example/v1/clustertesttype.go @@ -0,0 +1,89 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + apisexamplev1 "k8s.io/code-generator/examples/crd/apis/example/v1" + versioned "k8s.io/code-generator/examples/crd/clientset/versioned" + internalinterfaces "k8s.io/code-generator/examples/crd/informers/externalversions/internalinterfaces" + examplev1 "k8s.io/code-generator/examples/crd/listers/example/v1" +) + +// ClusterTestTypeInformer provides access to a shared informer and lister for +// ClusterTestTypes. +type ClusterTestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() examplev1.ClusterTestTypeLister +} + +type clusterTestTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewClusterTestTypeInformer constructs a new informer for ClusterTestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewClusterTestTypeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredClusterTestTypeInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredClusterTestTypeInformer constructs a new informer for ClusterTestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredClusterTestTypeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().ClusterTestTypes().List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().ClusterTestTypes().Watch(context.TODO(), options) + }, + }, + &apisexamplev1.ClusterTestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *clusterTestTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredClusterTestTypeInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *clusterTestTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apisexamplev1.ClusterTestType{}, f.defaultInformer) +} + +func (f *clusterTestTypeInformer) Lister() examplev1.ClusterTestTypeLister { + return examplev1.NewClusterTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/code-generator/examples/crd/informers/externalversions/example/v1/interface.go b/code-generator/examples/crd/informers/externalversions/example/v1/interface.go new file mode 100644 index 000000000..4c38e168e --- /dev/null +++ b/code-generator/examples/crd/informers/externalversions/example/v1/interface.go @@ -0,0 +1,52 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "k8s.io/code-generator/examples/crd/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // ClusterTestTypes returns a ClusterTestTypeInformer. + ClusterTestTypes() ClusterTestTypeInformer + // TestTypes returns a TestTypeInformer. + TestTypes() TestTypeInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// ClusterTestTypes returns a ClusterTestTypeInformer. +func (v *version) ClusterTestTypes() ClusterTestTypeInformer { + return &clusterTestTypeInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + +// TestTypes returns a TestTypeInformer. +func (v *version) TestTypes() TestTypeInformer { + return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/code-generator/examples/crd/informers/externalversions/example/v1/testtype.go b/code-generator/examples/crd/informers/externalversions/example/v1/testtype.go new file mode 100644 index 000000000..9655cb041 --- /dev/null +++ b/code-generator/examples/crd/informers/externalversions/example/v1/testtype.go @@ -0,0 +1,90 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + apisexamplev1 "k8s.io/code-generator/examples/crd/apis/example/v1" + versioned "k8s.io/code-generator/examples/crd/clientset/versioned" + internalinterfaces "k8s.io/code-generator/examples/crd/informers/externalversions/internalinterfaces" + examplev1 "k8s.io/code-generator/examples/crd/listers/example/v1" +) + +// TestTypeInformer provides access to a shared informer and lister for +// TestTypes. +type TestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() examplev1.TestTypeLister +} + +type testTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().TestTypes(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().TestTypes(namespace).Watch(context.TODO(), options) + }, + }, + &apisexamplev1.TestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *testTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apisexamplev1.TestType{}, f.defaultInformer) +} + +func (f *testTypeInformer) Lister() examplev1.TestTypeLister { + return examplev1.NewTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/code-generator/examples/crd/informers/externalversions/example2/interface.go b/code-generator/examples/crd/informers/externalversions/example2/interface.go new file mode 100644 index 000000000..5efd9bdcd --- /dev/null +++ b/code-generator/examples/crd/informers/externalversions/example2/interface.go @@ -0,0 +1,46 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package example2 + +import ( + v1 "k8s.io/code-generator/examples/crd/informers/externalversions/example2/v1" + internalinterfaces "k8s.io/code-generator/examples/crd/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/code-generator/examples/crd/informers/externalversions/example2/v1/interface.go b/code-generator/examples/crd/informers/externalversions/example2/v1/interface.go new file mode 100644 index 000000000..d6c18a3a6 --- /dev/null +++ b/code-generator/examples/crd/informers/externalversions/example2/v1/interface.go @@ -0,0 +1,45 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "k8s.io/code-generator/examples/crd/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // TestTypes returns a TestTypeInformer. + TestTypes() TestTypeInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// TestTypes returns a TestTypeInformer. +func (v *version) TestTypes() TestTypeInformer { + return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/code-generator/examples/crd/informers/externalversions/example2/v1/testtype.go b/code-generator/examples/crd/informers/externalversions/example2/v1/testtype.go new file mode 100644 index 000000000..30cc7ca4e --- /dev/null +++ b/code-generator/examples/crd/informers/externalversions/example2/v1/testtype.go @@ -0,0 +1,90 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + apisexample2v1 "k8s.io/code-generator/examples/crd/apis/example2/v1" + versioned "k8s.io/code-generator/examples/crd/clientset/versioned" + internalinterfaces "k8s.io/code-generator/examples/crd/informers/externalversions/internalinterfaces" + example2v1 "k8s.io/code-generator/examples/crd/listers/example2/v1" +) + +// TestTypeInformer provides access to a shared informer and lister for +// TestTypes. +type TestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() example2v1.TestTypeLister +} + +type testTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.SecondExampleV1().TestTypes(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.SecondExampleV1().TestTypes(namespace).Watch(context.TODO(), options) + }, + }, + &apisexample2v1.TestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *testTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&apisexample2v1.TestType{}, f.defaultInformer) +} + +func (f *testTypeInformer) Lister() example2v1.TestTypeLister { + return example2v1.NewTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/code-generator/examples/crd/informers/externalversions/factory.go b/code-generator/examples/crd/informers/externalversions/factory.go new file mode 100644 index 000000000..f5bf1c2ad --- /dev/null +++ b/code-generator/examples/crd/informers/externalversions/factory.go @@ -0,0 +1,274 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + versioned "k8s.io/code-generator/examples/crd/clientset/versioned" + conflicting "k8s.io/code-generator/examples/crd/informers/externalversions/conflicting" + example "k8s.io/code-generator/examples/crd/informers/externalversions/example" + example2 "k8s.io/code-generator/examples/crd/informers/externalversions/example2" + internalinterfaces "k8s.io/code-generator/examples/crd/informers/externalversions/internalinterfaces" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + transform cache.TransformFunc + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool + // wg tracks how many goroutines were started. + wg sync.WaitGroup + // shuttingDown is true when Shutdown has been called. It may still be running + // because it needs to wait for goroutines. + shuttingDown bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// WithTransform sets a transform on all informers. +func WithTransform(transform cache.TransformFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.transform = transform + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + if f.shuttingDown { + return + } + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + f.wg.Add(1) + // We need a new variable in each loop iteration, + // otherwise the goroutine would use the loop variable + // and that keeps changing. + informer := informer + go func() { + defer f.wg.Done() + informer.Run(stopCh) + }() + f.startedInformers[informerType] = true + } + } +} + +func (f *sharedInformerFactory) Shutdown() { + f.lock.Lock() + f.shuttingDown = true + f.lock.Unlock() + + // Will return immediately if there is nothing to wait for. + f.wg.Wait() +} + +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + informer.SetTransform(f.transform) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +// +// It is typically used like this: +// +// ctx, cancel := context.Background() +// defer cancel() +// factory := NewSharedInformerFactory(client, resyncPeriod) +// defer factory.WaitForStop() // Returns immediately if nothing was started. +// genericInformer := factory.ForResource(resource) +// typedInformer := factory.SomeAPIGroup().V1().SomeType() +// factory.Start(ctx.Done()) // Start processing these informers. +// synced := factory.WaitForCacheSync(ctx.Done()) +// for v, ok := range synced { +// if !ok { +// fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v) +// return +// } +// } +// +// // Creating informers can also be created after Start, but then +// // Start must be called again: +// anotherGenericInformer := factory.ForResource(resource) +// factory.Start(ctx.Done()) +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + + // Start initializes all requested informers. They are handled in goroutines + // which run until the stop channel gets closed. + // Warning: Start does not block. When run in a go-routine, it will race with a later WaitForCacheSync. + Start(stopCh <-chan struct{}) + + // Shutdown marks a factory as shutting down. At that point no new + // informers can be started anymore and Start will return without + // doing anything. + // + // In addition, Shutdown blocks until all goroutines have terminated. For that + // to happen, the close channel(s) that they were started with must be closed, + // either before Shutdown gets called or while it is waiting. + // + // Shutdown may be called multiple times, even concurrently. All such calls will + // block until all goroutines have terminated. + Shutdown() + + // WaitForCacheSync blocks until all started informers' caches were synced + // or the stop channel gets closed. + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + // ForResource gives generic access to a shared informer of the matching type. + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + + // InformerFor returns the SharedIndexInformer for obj using an internal + // client. + InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer + + ConflictingExample() conflicting.Interface + Example() example.Interface + SecondExample() example2.Interface +} + +func (f *sharedInformerFactory) ConflictingExample() conflicting.Interface { + return conflicting.New(f, f.namespace, f.tweakListOptions) +} + +func (f *sharedInformerFactory) Example() example.Interface { + return example.New(f, f.namespace, f.tweakListOptions) +} + +func (f *sharedInformerFactory) SecondExample() example2.Interface { + return example2.New(f, f.namespace, f.tweakListOptions) +} diff --git a/code-generator/examples/crd/informers/externalversions/generic.go b/code-generator/examples/crd/informers/externalversions/generic.go new file mode 100644 index 000000000..54b9cfbb9 --- /dev/null +++ b/code-generator/examples/crd/informers/externalversions/generic.go @@ -0,0 +1,74 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + fmt "fmt" + + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + v1 "k8s.io/code-generator/examples/crd/apis/conflicting/v1" + examplev1 "k8s.io/code-generator/examples/crd/apis/example/v1" + example2v1 "k8s.io/code-generator/examples/crd/apis/example2/v1" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=conflicting.test.crd.code-generator.k8s.io, Version=v1 + case v1.SchemeGroupVersion.WithResource("testtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.ConflictingExample().V1().TestTypes().Informer()}, nil + + // Group=example.crd.code-generator.k8s.io, Version=v1 + case examplev1.SchemeGroupVersion.WithResource("clustertesttypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Example().V1().ClusterTestTypes().Informer()}, nil + case examplev1.SchemeGroupVersion.WithResource("testtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Example().V1().TestTypes().Informer()}, nil + + // Group=example.test.crd.code-generator.k8s.io, Version=v1 + case example2v1.SchemeGroupVersion.WithResource("testtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.SecondExample().V1().TestTypes().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go b/code-generator/examples/crd/informers/externalversions/internalinterfaces/factory_interfaces.go similarity index 94% rename from pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go rename to code-generator/examples/crd/informers/externalversions/internalinterfaces/factory_interfaces.go index 71c802bab..4e150f3b7 100644 --- a/pkg/generated/informers/externalversions/internalinterfaces/factory_interfaces.go +++ b/code-generator/examples/crd/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -24,7 +24,7 @@ import ( v1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" cache "k8s.io/client-go/tools/cache" - versioned "k8s.io/sample-controller/pkg/generated/clientset/versioned" + versioned "k8s.io/code-generator/examples/crd/clientset/versioned" ) // NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. diff --git a/code-generator/examples/crd/listers/conflicting/v1/expansion_generated.go b/code-generator/examples/crd/listers/conflicting/v1/expansion_generated.go new file mode 100644 index 000000000..0192e05f0 --- /dev/null +++ b/code-generator/examples/crd/listers/conflicting/v1/expansion_generated.go @@ -0,0 +1,27 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// TestTypeListerExpansion allows custom methods to be added to +// TestTypeLister. +type TestTypeListerExpansion interface{} + +// TestTypeNamespaceListerExpansion allows custom methods to be added to +// TestTypeNamespaceLister. +type TestTypeNamespaceListerExpansion interface{} diff --git a/code-generator/examples/crd/listers/conflicting/v1/testtype.go b/code-generator/examples/crd/listers/conflicting/v1/testtype.go new file mode 100644 index 000000000..f1ab5b8b6 --- /dev/null +++ b/code-generator/examples/crd/listers/conflicting/v1/testtype.go @@ -0,0 +1,70 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" + conflictingv1 "k8s.io/code-generator/examples/crd/apis/conflicting/v1" +) + +// TestTypeLister helps list TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeLister interface { + // List lists all TestTypes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*conflictingv1.TestType, err error) + // TestTypes returns an object that can list and get TestTypes. + TestTypes(namespace string) TestTypeNamespaceLister + TestTypeListerExpansion +} + +// testTypeLister implements the TestTypeLister interface. +type testTypeLister struct { + listers.ResourceIndexer[*conflictingv1.TestType] +} + +// NewTestTypeLister returns a new TestTypeLister. +func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { + return &testTypeLister{listers.New[*conflictingv1.TestType](indexer, conflictingv1.Resource("testtype"))} +} + +// TestTypes returns an object that can list and get TestTypes. +func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { + return testTypeNamespaceLister{listers.NewNamespaced[*conflictingv1.TestType](s.ResourceIndexer, namespace)} +} + +// TestTypeNamespaceLister helps list and get TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeNamespaceLister interface { + // List lists all TestTypes in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*conflictingv1.TestType, err error) + // Get retrieves the TestType from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*conflictingv1.TestType, error) + TestTypeNamespaceListerExpansion +} + +// testTypeNamespaceLister implements the TestTypeNamespaceLister +// interface. +type testTypeNamespaceLister struct { + listers.ResourceIndexer[*conflictingv1.TestType] +} diff --git a/code-generator/examples/crd/listers/example/v1/clustertesttype.go b/code-generator/examples/crd/listers/example/v1/clustertesttype.go new file mode 100644 index 000000000..612ea8ba5 --- /dev/null +++ b/code-generator/examples/crd/listers/example/v1/clustertesttype.go @@ -0,0 +1,48 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" + examplev1 "k8s.io/code-generator/examples/crd/apis/example/v1" +) + +// ClusterTestTypeLister helps list ClusterTestTypes. +// All objects returned here must be treated as read-only. +type ClusterTestTypeLister interface { + // List lists all ClusterTestTypes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*examplev1.ClusterTestType, err error) + // Get retrieves the ClusterTestType from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*examplev1.ClusterTestType, error) + ClusterTestTypeListerExpansion +} + +// clusterTestTypeLister implements the ClusterTestTypeLister interface. +type clusterTestTypeLister struct { + listers.ResourceIndexer[*examplev1.ClusterTestType] +} + +// NewClusterTestTypeLister returns a new ClusterTestTypeLister. +func NewClusterTestTypeLister(indexer cache.Indexer) ClusterTestTypeLister { + return &clusterTestTypeLister{listers.New[*examplev1.ClusterTestType](indexer, examplev1.Resource("clustertesttype"))} +} diff --git a/code-generator/examples/crd/listers/example/v1/expansion_generated.go b/code-generator/examples/crd/listers/example/v1/expansion_generated.go new file mode 100644 index 000000000..2681a29f4 --- /dev/null +++ b/code-generator/examples/crd/listers/example/v1/expansion_generated.go @@ -0,0 +1,31 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// ClusterTestTypeListerExpansion allows custom methods to be added to +// ClusterTestTypeLister. +type ClusterTestTypeListerExpansion interface{} + +// TestTypeListerExpansion allows custom methods to be added to +// TestTypeLister. +type TestTypeListerExpansion interface{} + +// TestTypeNamespaceListerExpansion allows custom methods to be added to +// TestTypeNamespaceLister. +type TestTypeNamespaceListerExpansion interface{} diff --git a/code-generator/examples/crd/listers/example/v1/testtype.go b/code-generator/examples/crd/listers/example/v1/testtype.go new file mode 100644 index 000000000..9ba7d4005 --- /dev/null +++ b/code-generator/examples/crd/listers/example/v1/testtype.go @@ -0,0 +1,70 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" + examplev1 "k8s.io/code-generator/examples/crd/apis/example/v1" +) + +// TestTypeLister helps list TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeLister interface { + // List lists all TestTypes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*examplev1.TestType, err error) + // TestTypes returns an object that can list and get TestTypes. + TestTypes(namespace string) TestTypeNamespaceLister + TestTypeListerExpansion +} + +// testTypeLister implements the TestTypeLister interface. +type testTypeLister struct { + listers.ResourceIndexer[*examplev1.TestType] +} + +// NewTestTypeLister returns a new TestTypeLister. +func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { + return &testTypeLister{listers.New[*examplev1.TestType](indexer, examplev1.Resource("testtype"))} +} + +// TestTypes returns an object that can list and get TestTypes. +func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { + return testTypeNamespaceLister{listers.NewNamespaced[*examplev1.TestType](s.ResourceIndexer, namespace)} +} + +// TestTypeNamespaceLister helps list and get TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeNamespaceLister interface { + // List lists all TestTypes in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*examplev1.TestType, err error) + // Get retrieves the TestType from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*examplev1.TestType, error) + TestTypeNamespaceListerExpansion +} + +// testTypeNamespaceLister implements the TestTypeNamespaceLister +// interface. +type testTypeNamespaceLister struct { + listers.ResourceIndexer[*examplev1.TestType] +} diff --git a/code-generator/examples/crd/listers/example2/v1/expansion_generated.go b/code-generator/examples/crd/listers/example2/v1/expansion_generated.go new file mode 100644 index 000000000..0192e05f0 --- /dev/null +++ b/code-generator/examples/crd/listers/example2/v1/expansion_generated.go @@ -0,0 +1,27 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// TestTypeListerExpansion allows custom methods to be added to +// TestTypeLister. +type TestTypeListerExpansion interface{} + +// TestTypeNamespaceListerExpansion allows custom methods to be added to +// TestTypeNamespaceLister. +type TestTypeNamespaceListerExpansion interface{} diff --git a/code-generator/examples/crd/listers/example2/v1/testtype.go b/code-generator/examples/crd/listers/example2/v1/testtype.go new file mode 100644 index 000000000..3763c397b --- /dev/null +++ b/code-generator/examples/crd/listers/example2/v1/testtype.go @@ -0,0 +1,70 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" + example2v1 "k8s.io/code-generator/examples/crd/apis/example2/v1" +) + +// TestTypeLister helps list TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeLister interface { + // List lists all TestTypes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*example2v1.TestType, err error) + // TestTypes returns an object that can list and get TestTypes. + TestTypes(namespace string) TestTypeNamespaceLister + TestTypeListerExpansion +} + +// testTypeLister implements the TestTypeLister interface. +type testTypeLister struct { + listers.ResourceIndexer[*example2v1.TestType] +} + +// NewTestTypeLister returns a new TestTypeLister. +func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { + return &testTypeLister{listers.New[*example2v1.TestType](indexer, example2v1.Resource("testtype"))} +} + +// TestTypes returns an object that can list and get TestTypes. +func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { + return testTypeNamespaceLister{listers.NewNamespaced[*example2v1.TestType](s.ResourceIndexer, namespace)} +} + +// TestTypeNamespaceLister helps list and get TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeNamespaceLister interface { + // List lists all TestTypes in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*example2v1.TestType, err error) + // Get retrieves the TestType from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*example2v1.TestType, error) + TestTypeNamespaceListerExpansion +} + +// testTypeNamespaceLister implements the TestTypeNamespaceLister +// interface. +type testTypeNamespaceLister struct { + listers.ResourceIndexer[*example2v1.TestType] +} diff --git a/code-generator/examples/go.mod b/code-generator/examples/go.mod new file mode 100644 index 000000000..7494428e1 --- /dev/null +++ b/code-generator/examples/go.mod @@ -0,0 +1,60 @@ +// This is a submodule to isolate k8s.io/code-generator from k8s.io/{api,apimachinery,client-go} dependencies in generated code + +module k8s.io/code-generator/examples + +go 1.23.0 + +godebug default=go1.23 + +require ( + k8s.io/api v0.0.0 + k8s.io/apimachinery v0.0.0 + k8s.io/client-go v0.0.0 + k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 +) + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/x448/float16 v0.8.4 // indirect + golang.org/x/net v0.28.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/sys v0.23.0 // indirect + golang.org/x/term v0.23.0 // indirect + golang.org/x/text v0.17.0 // indirect + golang.org/x/time v0.3.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/yaml v1.4.0 // indirect +) + +replace ( + k8s.io/api => ../../api + k8s.io/apimachinery => ../../apimachinery + k8s.io/client-go => ../../client-go +) diff --git a/code-generator/examples/go.sum b/code-generator/examples/go.sum new file mode 100644 index 000000000..05d6a16ad --- /dev/null +++ b/code-generator/examples/go.sum @@ -0,0 +1,151 @@ +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 h1:GKE9U8BH16uynoxQii0auTjmmmuZ3O0LFMN6S0lPPhI= +k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/code-generator/examples/go.work b/code-generator/examples/go.work new file mode 100644 index 000000000..ec2af5afc --- /dev/null +++ b/code-generator/examples/go.work @@ -0,0 +1,8 @@ +// This is a hack, but it prevents go from climbing further and trying to +// reconcile the various deps across the "real" modules and this one. + +go 1.23.0 + +godebug default=go1.23 + +use . diff --git a/code-generator/examples/hack/boilerplate.go.txt b/code-generator/examples/hack/boilerplate.go.txt new file mode 100644 index 000000000..b7c650da4 --- /dev/null +++ b/code-generator/examples/hack/boilerplate.go.txt @@ -0,0 +1,16 @@ +/* +Copyright The Kubernetes 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. +*/ + diff --git a/code-generator/examples/hack/update-codegen.sh b/code-generator/examples/hack/update-codegen.sh new file mode 100755 index 000000000..2f9a734cd --- /dev/null +++ b/code-generator/examples/hack/update-codegen.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash + +# Copyright 2017 The Kubernetes 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 + +SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")" +SCRIPT_ROOT="${SCRIPT_DIR}/.." +CODEGEN_PKG="${CODEGEN_PKG:-"${SCRIPT_ROOT}/.."}" + +source "${CODEGEN_PKG}/kube_codegen.sh" + +THIS_PKG="k8s.io/code-generator/examples" + +kube::codegen::gen_helpers \ + --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \ + "${SCRIPT_ROOT}" + +if [[ -n "${API_KNOWN_VIOLATIONS_DIR:-}" ]]; then + report_filename="${API_KNOWN_VIOLATIONS_DIR}/codegen_violation_exceptions.list" + if [[ "${UPDATE_API_KNOWN_VIOLATIONS:-}" == "true" ]]; then + update_report="--update-report" + fi +fi + +kube::codegen::gen_openapi \ + --output-dir "${SCRIPT_ROOT}/apiserver/openapi" \ + --output-pkg "k8s.io/${THIS_PKG}/apiserver/openapi" \ + --report-filename "${report_filename:-"/dev/null"}" \ + ${update_report:+"${update_report}"} \ + --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \ + "${SCRIPT_ROOT}/apiserver/apis" + +kube::codegen::gen_client \ + --with-watch \ + --output-dir "${SCRIPT_ROOT}/apiserver" \ + --output-pkg "${THIS_PKG}/apiserver" \ + --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \ + "${SCRIPT_ROOT}/apiserver/apis" + +kube::codegen::gen_client \ + --with-watch \ + --with-applyconfig \ + --output-dir "${SCRIPT_ROOT}/crd" \ + --output-pkg "${THIS_PKG}/crd" \ + --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \ + "${SCRIPT_ROOT}/crd/apis" + +kube::codegen::gen_client \ + --with-watch \ + --with-applyconfig \ + --output-dir "${SCRIPT_ROOT}/single" \ + --output-pkg "${THIS_PKG}/single" \ + --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \ + --one-input-api "api" \ + "${SCRIPT_ROOT}/single" + +kube::codegen::gen_client \ + --with-watch \ + --with-applyconfig \ + --output-dir "${SCRIPT_ROOT}/MixedCase" \ + --output-pkg "${THIS_PKG}/MixedCase" \ + --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \ + "${SCRIPT_ROOT}/MixedCase/apis" + +kube::codegen::gen_client \ + --with-watch \ + --with-applyconfig \ + --output-dir "${SCRIPT_ROOT}/HyphenGroup" \ + --output-pkg "${THIS_PKG}/HyphenGroup" \ + --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \ + "${SCRIPT_ROOT}/HyphenGroup/apis" diff --git a/code-generator/examples/hack/verify-codegen.sh b/code-generator/examples/hack/verify-codegen.sh new file mode 100755 index 000000000..789f28472 --- /dev/null +++ b/code-generator/examples/hack/verify-codegen.sh @@ -0,0 +1,54 @@ +#!/usr/bin/env bash + +# Copyright 2017 The Kubernetes 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 + +SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd -P)" +DIFFROOT="${SCRIPT_ROOT}" +TMP_DIFFROOT="$(mktemp -d -t "$(basename "$0").XXXXXX")" + +cleanup() { + rm -rf "${TMP_DIFFROOT}" +} +trap "cleanup" EXIT SIGINT + +cleanup + +mkdir -p "${TMP_DIFFROOT}" +cp -a "${DIFFROOT}"/* "${TMP_DIFFROOT}" + +"${SCRIPT_ROOT}/hack/update-codegen.sh" +echo "diffing ${DIFFROOT} against freshly generated codegen" +ret=0 +diff -Naupr "${DIFFROOT}" "${TMP_DIFFROOT}" || ret=$? +if [[ $ret -eq 0 ]]; then + echo "${DIFFROOT} up to date." +else + echo "${DIFFROOT} is out of date. Please run hack/update-codegen.sh" + exit 1 +fi + +# smoke test +echo "Smoke testing examples by compiling..." +pushd "${SCRIPT_ROOT}" + go build "k8s.io/code-generator/examples/crd/..." + go build "k8s.io/code-generator/examples/single/..." + go build "k8s.io/code-generator/examples/apiserver/..." + go build "k8s.io/code-generator/examples/MixedCase/..." + go build "k8s.io/code-generator/examples/HyphenGroup/..." +popd diff --git a/code-generator/examples/single/api/v1/doc.go b/code-generator/examples/single/api/v1/doc.go new file mode 100644 index 000000000..89647413b --- /dev/null +++ b/code-generator/examples/single/api/v1/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2016 The Kubernetes 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. +*/ + +// +k8s:deepcopy-gen=package +// +k8s:defaulter-gen=TypeMeta +// +groupName=example.crd.code-generator.k8s.io + +package v1 // import "k8s.io/code-generator/examples/crd/apis/example/v1" diff --git a/code-generator/examples/single/api/v1/register.go b/code-generator/examples/single/api/v1/register.go new file mode 100644 index 000000000..58371e0e9 --- /dev/null +++ b/code-generator/examples/single/api/v1/register.go @@ -0,0 +1,59 @@ +/* +Copyright 2015 The Kubernetes 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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +var SchemeGroupVersion = schema.GroupVersion{Group: "example.crd.code-generator.k8s.io", Version: "v1"} + +var ( + // TODO: move SchemeBuilder with zz_generated.deepcopy.go to k8s.io/api. + // localSchemeBuilder and AddToScheme will stay in k8s.io/kubernetes. + SchemeBuilder runtime.SchemeBuilder + localSchemeBuilder = &SchemeBuilder + AddToScheme = localSchemeBuilder.AddToScheme +) + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + localSchemeBuilder.Register(addKnownTypes) +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Adds the list of known types to the given scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &TestType{}, + &TestTypeList{}, + ) + + scheme.AddKnownTypes(SchemeGroupVersion, + &metav1.Status{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/code-generator/examples/single/api/v1/types.go b/code-generator/examples/single/api/v1/types.go new file mode 100644 index 000000000..f1bd68f49 --- /dev/null +++ b/code-generator/examples/single/api/v1/types.go @@ -0,0 +1,75 @@ +/* +Copyright 2015 The Kubernetes 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 v1 + +import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestType is a top-level type. A client is created for it. +type TestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status TestTypeStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TestTypeList is a top-level list type. The client methods for lists are automatically created. +// You are not supposed to create a separated client for this one. +type TestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + + Items []TestType `json:"items"` +} + +type TestTypeStatus struct { + Blah string `json:"blah"` +} + +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +type ClusterTestTypeList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + Items []ClusterTestType `json:"items"` +} + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +genclient:method=GetScale,verb=get,subresource=scale,result=k8s.io/api/autoscaling/v1.Scale +// +genclient:method=UpdateScale,verb=update,subresource=scale,input=k8s.io/api/autoscaling/v1.Scale,result=k8s.io/api/autoscaling/v1.Scale + +type ClusterTestType struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + // +optional + Status ClusterTestTypeStatus `json:"status,omitempty"` +} + +type ClusterTestTypeStatus struct { + Blah string `json:"blah"` +} diff --git a/code-generator/examples/single/api/v1/zz_generated.deepcopy.go b/code-generator/examples/single/api/v1/zz_generated.deepcopy.go new file mode 100644 index 000000000..5eee47016 --- /dev/null +++ b/code-generator/examples/single/api/v1/zz_generated.deepcopy.go @@ -0,0 +1,178 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestType) DeepCopyInto(out *ClusterTestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestType. +func (in *ClusterTestType) DeepCopy() *ClusterTestType { + if in == nil { + return nil + } + out := new(ClusterTestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterTestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestTypeList) DeepCopyInto(out *ClusterTestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ClusterTestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestTypeList. +func (in *ClusterTestTypeList) DeepCopy() *ClusterTestTypeList { + if in == nil { + return nil + } + out := new(ClusterTestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ClusterTestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ClusterTestTypeStatus) DeepCopyInto(out *ClusterTestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterTestTypeStatus. +func (in *ClusterTestTypeStatus) DeepCopy() *ClusterTestTypeStatus { + if in == nil { + return nil + } + out := new(ClusterTestTypeStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestType) DeepCopyInto(out *TestType) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Status = in.Status + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestType. +func (in *TestType) DeepCopy() *TestType { + if in == nil { + return nil + } + out := new(TestType) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestType) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeList) DeepCopyInto(out *TestTypeList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TestType, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeList. +func (in *TestTypeList) DeepCopy() *TestTypeList { + if in == nil { + return nil + } + out := new(TestTypeList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TestTypeList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TestTypeStatus) DeepCopyInto(out *TestTypeStatus) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TestTypeStatus. +func (in *TestTypeStatus) DeepCopy() *TestTypeStatus { + if in == nil { + return nil + } + out := new(TestTypeStatus) + in.DeepCopyInto(out) + return out +} diff --git a/code-generator/examples/single/api/v1/zz_generated.defaults.go b/code-generator/examples/single/api/v1/zz_generated.defaults.go new file mode 100644 index 000000000..dac177e93 --- /dev/null +++ b/code-generator/examples/single/api/v1/zz_generated.defaults.go @@ -0,0 +1,33 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by defaulter-gen. DO NOT EDIT. + +package v1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// RegisterDefaults adds defaulters functions to the given scheme. +// Public to allow building arbitrary schemes. +// All generated defaulters are covering - they call all nested defaulters. +func RegisterDefaults(scheme *runtime.Scheme) error { + return nil +} diff --git a/code-generator/examples/single/applyconfiguration/api/v1/clustertesttype.go b/code-generator/examples/single/applyconfiguration/api/v1/clustertesttype.go new file mode 100644 index 000000000..49ceb182a --- /dev/null +++ b/code-generator/examples/single/applyconfiguration/api/v1/clustertesttype.go @@ -0,0 +1,215 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +import ( + apismetav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + metav1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// ClusterTestTypeApplyConfiguration represents a declarative configuration of the ClusterTestType type for use +// with apply. +type ClusterTestTypeApplyConfiguration struct { + metav1.TypeMetaApplyConfiguration `json:",inline"` + *metav1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Status *ClusterTestTypeStatusApplyConfiguration `json:"status,omitempty"` +} + +// ClusterTestType constructs a declarative configuration of the ClusterTestType type for use with +// apply. +func ClusterTestType(name string) *ClusterTestTypeApplyConfiguration { + b := &ClusterTestTypeApplyConfiguration{} + b.WithName(name) + b.WithKind("ClusterTestType") + b.WithAPIVersion("example.crd.code-generator.k8s.io/v1") + return b +} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithKind(value string) *ClusterTestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithAPIVersion(value string) *ClusterTestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithName(value string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithGenerateName(value string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithNamespace(value string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithUID(value types.UID) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithResourceVersion(value string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithGeneration(value int64) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithCreationTimestamp(value apismetav1.Time) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithDeletionTimestamp(value apismetav1.Time) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *ClusterTestTypeApplyConfiguration) WithLabels(entries map[string]string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *ClusterTestTypeApplyConfiguration) WithAnnotations(entries map[string]string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *ClusterTestTypeApplyConfiguration) WithOwnerReferences(values ...*metav1.OwnerReferenceApplyConfiguration) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *ClusterTestTypeApplyConfiguration) WithFinalizers(values ...string) *ClusterTestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *ClusterTestTypeApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &metav1.ObjectMetaApplyConfiguration{} + } +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *ClusterTestTypeApplyConfiguration) WithStatus(value *ClusterTestTypeStatusApplyConfiguration) *ClusterTestTypeApplyConfiguration { + b.Status = value + return b +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *ClusterTestTypeApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} diff --git a/code-generator/examples/single/applyconfiguration/api/v1/clustertesttypestatus.go b/code-generator/examples/single/applyconfiguration/api/v1/clustertesttypestatus.go new file mode 100644 index 000000000..c2ccfa581 --- /dev/null +++ b/code-generator/examples/single/applyconfiguration/api/v1/clustertesttypestatus.go @@ -0,0 +1,39 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// ClusterTestTypeStatusApplyConfiguration represents a declarative configuration of the ClusterTestTypeStatus type for use +// with apply. +type ClusterTestTypeStatusApplyConfiguration struct { + Blah *string `json:"blah,omitempty"` +} + +// ClusterTestTypeStatusApplyConfiguration constructs a declarative configuration of the ClusterTestTypeStatus type for use with +// apply. +func ClusterTestTypeStatus() *ClusterTestTypeStatusApplyConfiguration { + return &ClusterTestTypeStatusApplyConfiguration{} +} + +// WithBlah sets the Blah field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Blah field is set to the value of the last call. +func (b *ClusterTestTypeStatusApplyConfiguration) WithBlah(value string) *ClusterTestTypeStatusApplyConfiguration { + b.Blah = &value + return b +} diff --git a/code-generator/examples/single/applyconfiguration/api/v1/testtype.go b/code-generator/examples/single/applyconfiguration/api/v1/testtype.go new file mode 100644 index 000000000..49fdd2a66 --- /dev/null +++ b/code-generator/examples/single/applyconfiguration/api/v1/testtype.go @@ -0,0 +1,216 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +import ( + apismetav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + metav1 "k8s.io/client-go/applyconfigurations/meta/v1" +) + +// TestTypeApplyConfiguration represents a declarative configuration of the TestType type for use +// with apply. +type TestTypeApplyConfiguration struct { + metav1.TypeMetaApplyConfiguration `json:",inline"` + *metav1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Status *TestTypeStatusApplyConfiguration `json:"status,omitempty"` +} + +// TestType constructs a declarative configuration of the TestType type for use with +// apply. +func TestType(name, namespace string) *TestTypeApplyConfiguration { + b := &TestTypeApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("TestType") + b.WithAPIVersion("example.crd.code-generator.k8s.io/v1") + return b +} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithKind(value string) *TestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithAPIVersion(value string) *TestTypeApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithName(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithGenerateName(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithNamespace(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithUID(value types.UID) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithResourceVersion(value string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithGeneration(value int64) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithCreationTimestamp(value apismetav1.Time) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithDeletionTimestamp(value apismetav1.Time) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *TestTypeApplyConfiguration) WithLabels(entries map[string]string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *TestTypeApplyConfiguration) WithAnnotations(entries map[string]string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *TestTypeApplyConfiguration) WithOwnerReferences(values ...*metav1.OwnerReferenceApplyConfiguration) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *TestTypeApplyConfiguration) WithFinalizers(values ...string) *TestTypeApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *TestTypeApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &metav1.ObjectMetaApplyConfiguration{} + } +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *TestTypeApplyConfiguration) WithStatus(value *TestTypeStatusApplyConfiguration) *TestTypeApplyConfiguration { + b.Status = value + return b +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *TestTypeApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} diff --git a/code-generator/examples/single/applyconfiguration/api/v1/testtypestatus.go b/code-generator/examples/single/applyconfiguration/api/v1/testtypestatus.go new file mode 100644 index 000000000..246b2ee18 --- /dev/null +++ b/code-generator/examples/single/applyconfiguration/api/v1/testtypestatus.go @@ -0,0 +1,39 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// TestTypeStatusApplyConfiguration represents a declarative configuration of the TestTypeStatus type for use +// with apply. +type TestTypeStatusApplyConfiguration struct { + Blah *string `json:"blah,omitempty"` +} + +// TestTypeStatusApplyConfiguration constructs a declarative configuration of the TestTypeStatus type for use with +// apply. +func TestTypeStatus() *TestTypeStatusApplyConfiguration { + return &TestTypeStatusApplyConfiguration{} +} + +// WithBlah sets the Blah field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Blah field is set to the value of the last call. +func (b *TestTypeStatusApplyConfiguration) WithBlah(value string) *TestTypeStatusApplyConfiguration { + b.Blah = &value + return b +} diff --git a/code-generator/examples/single/applyconfiguration/internal/internal.go b/code-generator/examples/single/applyconfiguration/internal/internal.go new file mode 100644 index 000000000..1064e227e --- /dev/null +++ b/code-generator/examples/single/applyconfiguration/internal/internal.go @@ -0,0 +1,62 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package internal + +import ( + fmt "fmt" + sync "sync" + + typed "sigs.k8s.io/structured-merge-diff/v4/typed" +) + +func Parser() *typed.Parser { + parserOnce.Do(func() { + var err error + parser, err = typed.NewParser(schemaYAML) + if err != nil { + panic(fmt.Sprintf("Failed to parse schema: %v", err)) + } + }) + return parser +} + +var parserOnce sync.Once +var parser *typed.Parser +var schemaYAML = typed.YAMLObject(`types: +- name: __untyped_atomic_ + scalar: untyped + list: + elementType: + namedType: __untyped_atomic_ + elementRelationship: atomic + map: + elementType: + namedType: __untyped_atomic_ + elementRelationship: atomic +- name: __untyped_deduced_ + scalar: untyped + list: + elementType: + namedType: __untyped_atomic_ + elementRelationship: atomic + map: + elementType: + namedType: __untyped_deduced_ + elementRelationship: separable +`) diff --git a/code-generator/examples/single/applyconfiguration/utils.go b/code-generator/examples/single/applyconfiguration/utils.go new file mode 100644 index 000000000..07079ed2b --- /dev/null +++ b/code-generator/examples/single/applyconfiguration/utils.go @@ -0,0 +1,50 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package applyconfiguration + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/single/api/v1" + apiv1 "k8s.io/code-generator/examples/single/applyconfiguration/api/v1" + internal "k8s.io/code-generator/examples/single/applyconfiguration/internal" +) + +// ForKind returns an apply configuration type for the given GroupVersionKind, or nil if no +// apply configuration type exists for the given GroupVersionKind. +func ForKind(kind schema.GroupVersionKind) interface{} { + switch kind { + // Group=example.crd.code-generator.k8s.io, Version=v1 + case v1.SchemeGroupVersion.WithKind("ClusterTestType"): + return &apiv1.ClusterTestTypeApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("ClusterTestTypeStatus"): + return &apiv1.ClusterTestTypeStatusApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("TestType"): + return &apiv1.TestTypeApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("TestTypeStatus"): + return &apiv1.TestTypeStatusApplyConfiguration{} + + } + return nil +} + +func NewTypeConverter(scheme *runtime.Scheme) *testing.TypeConverter { + return &testing.TypeConverter{Scheme: scheme, TypeResolver: internal.Parser()} +} diff --git a/code-generator/examples/single/clientset/versioned/clientset.go b/code-generator/examples/single/clientset/versioned/clientset.go new file mode 100644 index 000000000..90ff9fba1 --- /dev/null +++ b/code-generator/examples/single/clientset/versioned/clientset.go @@ -0,0 +1,120 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package versioned + +import ( + fmt "fmt" + http "net/http" + + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" + examplev1 "k8s.io/code-generator/examples/single/clientset/versioned/typed/api/v1" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + ExampleV1() examplev1.ExampleV1Interface +} + +// Clientset contains the clients for groups. +type Clientset struct { + *discovery.DiscoveryClient + exampleV1 *examplev1.ExampleV1Client +} + +// ExampleV1 retrieves the ExampleV1Client +func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { + return c.exampleV1 +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfig will generate a rate-limiter in configShallowCopy. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + + if configShallowCopy.UserAgent == "" { + configShallowCopy.UserAgent = rest.DefaultKubernetesUserAgent() + } + + // share the transport between all clients + httpClient, err := rest.HTTPClientFor(&configShallowCopy) + if err != nil { + return nil, err + } + + return NewForConfigAndClient(&configShallowCopy, httpClient) +} + +// NewForConfigAndClient creates a new Clientset for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +// If config's RateLimiter is not set and QPS and Burst are acceptable, +// NewForConfigAndClient will generate a rate-limiter in configShallowCopy. +func NewForConfigAndClient(c *rest.Config, httpClient *http.Client) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + if configShallowCopy.Burst <= 0 { + return nil, fmt.Errorf("burst is required to be greater than 0 when RateLimiter is not set and QPS is set to greater than 0") + } + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + + var cs Clientset + var err error + cs.exampleV1, err = examplev1.NewForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfigAndClient(&configShallowCopy, httpClient) + if err != nil { + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + cs, err := NewForConfig(c) + if err != nil { + panic(err) + } + return cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.exampleV1 = examplev1.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/pkg/generated/clientset/versioned/fake/clientset_generated.go b/code-generator/examples/single/clientset/versioned/fake/clientset_generated.go similarity index 62% rename from pkg/generated/clientset/versioned/fake/clientset_generated.go rename to code-generator/examples/single/clientset/versioned/fake/clientset_generated.go index c616856e1..d16257bc4 100644 --- a/pkg/generated/clientset/versioned/fake/clientset_generated.go +++ b/code-generator/examples/single/clientset/versioned/fake/clientset_generated.go @@ -24,9 +24,10 @@ import ( "k8s.io/client-go/discovery" fakediscovery "k8s.io/client-go/discovery/fake" "k8s.io/client-go/testing" - clientset "k8s.io/sample-controller/pkg/generated/clientset/versioned" - samplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1" - fakesamplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/fake" + applyconfiguration "k8s.io/code-generator/examples/single/applyconfiguration" + clientset "k8s.io/code-generator/examples/single/clientset/versioned" + examplev1 "k8s.io/code-generator/examples/single/clientset/versioned/typed/api/v1" + fakeexamplev1 "k8s.io/code-generator/examples/single/clientset/versioned/typed/api/v1/fake" ) // NewSimpleClientset returns a clientset that will respond with the provided objects. @@ -78,12 +79,44 @@ func (c *Clientset) Tracker() testing.ObjectTracker { return c.tracker } +// NewClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewClientset(objects ...runtime.Object) *Clientset { + o := testing.NewFieldManagedObjectTracker( + scheme, + codecs.UniversalDecoder(), + applyconfiguration.NewTypeConverter(scheme), + ) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{tracker: o} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + var ( _ clientset.Interface = &Clientset{} _ testing.FakeClient = &Clientset{} ) -// SamplecontrollerV1alpha1 retrieves the SamplecontrollerV1alpha1Client -func (c *Clientset) SamplecontrollerV1alpha1() samplecontrollerv1alpha1.SamplecontrollerV1alpha1Interface { - return &fakesamplecontrollerv1alpha1.FakeSamplecontrollerV1alpha1{Fake: &c.Fake} +// ExampleV1 retrieves the ExampleV1Client +func (c *Clientset) ExampleV1() examplev1.ExampleV1Interface { + return &fakeexamplev1.FakeExampleV1{Fake: &c.Fake} } diff --git a/code-generator/examples/single/clientset/versioned/fake/doc.go b/code-generator/examples/single/clientset/versioned/fake/doc.go new file mode 100644 index 000000000..9b99e7167 --- /dev/null +++ b/code-generator/examples/single/clientset/versioned/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/code-generator/examples/single/clientset/versioned/fake/register.go b/code-generator/examples/single/clientset/versioned/fake/register.go new file mode 100644 index 000000000..084c6bc8f --- /dev/null +++ b/code-generator/examples/single/clientset/versioned/fake/register.go @@ -0,0 +1,56 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + examplev1 "k8s.io/code-generator/examples/single/api/v1" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) + +var localSchemeBuilder = runtime.SchemeBuilder{ + examplev1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(scheme)) +} diff --git a/code-generator/examples/single/clientset/versioned/scheme/doc.go b/code-generator/examples/single/clientset/versioned/scheme/doc.go new file mode 100644 index 000000000..7dc375616 --- /dev/null +++ b/code-generator/examples/single/clientset/versioned/scheme/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/code-generator/examples/single/clientset/versioned/scheme/register.go b/code-generator/examples/single/clientset/versioned/scheme/register.go new file mode 100644 index 000000000..d54e5a32b --- /dev/null +++ b/code-generator/examples/single/clientset/versioned/scheme/register.go @@ -0,0 +1,56 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package scheme + +import ( + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + examplev1 "k8s.io/code-generator/examples/single/api/v1" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) +var localSchemeBuilder = runtime.SchemeBuilder{ + examplev1.AddToScheme, +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// _ = aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +var AddToScheme = localSchemeBuilder.AddToScheme + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + utilruntime.Must(AddToScheme(Scheme)) +} diff --git a/code-generator/examples/single/clientset/versioned/typed/api/v1/api_client.go b/code-generator/examples/single/clientset/versioned/typed/api/v1/api_client.go new file mode 100644 index 000000000..c1af1175e --- /dev/null +++ b/code-generator/examples/single/clientset/versioned/typed/api/v1/api_client.go @@ -0,0 +1,112 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + http "net/http" + + rest "k8s.io/client-go/rest" + apiv1 "k8s.io/code-generator/examples/single/api/v1" + scheme "k8s.io/code-generator/examples/single/clientset/versioned/scheme" +) + +type ExampleV1Interface interface { + RESTClient() rest.Interface + ClusterTestTypesGetter + TestTypesGetter +} + +// ExampleV1Client is used to interact with features provided by the example.crd.code-generator.k8s.io group. +type ExampleV1Client struct { + restClient rest.Interface +} + +func (c *ExampleV1Client) ClusterTestTypes() ClusterTestTypeInterface { + return newClusterTestTypes(c) +} + +func (c *ExampleV1Client) TestTypes(namespace string) TestTypeInterface { + return newTestTypes(c, namespace) +} + +// NewForConfig creates a new ExampleV1Client for the given config. +// NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), +// where httpClient was generated with rest.HTTPClientFor(c). +func NewForConfig(c *rest.Config) (*ExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + httpClient, err := rest.HTTPClientFor(&config) + if err != nil { + return nil, err + } + return NewForConfigAndClient(&config, httpClient) +} + +// NewForConfigAndClient creates a new ExampleV1Client for the given config and http client. +// Note the http client provided takes precedence over the configured transport values. +func NewForConfigAndClient(c *rest.Config, h *http.Client) (*ExampleV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientForConfigAndClient(&config, h) + if err != nil { + return nil, err + } + return &ExampleV1Client{client}, nil +} + +// NewForConfigOrDie creates a new ExampleV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ExampleV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ExampleV1Client for the given RESTClient. +func New(c rest.Interface) *ExampleV1Client { + return &ExampleV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := apiv1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *ExampleV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/code-generator/examples/single/clientset/versioned/typed/api/v1/clustertesttype.go b/code-generator/examples/single/clientset/versioned/typed/api/v1/clustertesttype.go new file mode 100644 index 000000000..5536ac2a0 --- /dev/null +++ b/code-generator/examples/single/clientset/versioned/typed/api/v1/clustertesttype.go @@ -0,0 +1,104 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + + autoscalingv1 "k8s.io/api/autoscaling/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + apiv1 "k8s.io/code-generator/examples/single/api/v1" + applyconfigurationapiv1 "k8s.io/code-generator/examples/single/applyconfiguration/api/v1" + scheme "k8s.io/code-generator/examples/single/clientset/versioned/scheme" +) + +// ClusterTestTypesGetter has a method to return a ClusterTestTypeInterface. +// A group's client should implement this interface. +type ClusterTestTypesGetter interface { + ClusterTestTypes() ClusterTestTypeInterface +} + +// ClusterTestTypeInterface has methods to work with ClusterTestType resources. +type ClusterTestTypeInterface interface { + Create(ctx context.Context, clusterTestType *apiv1.ClusterTestType, opts metav1.CreateOptions) (*apiv1.ClusterTestType, error) + Update(ctx context.Context, clusterTestType *apiv1.ClusterTestType, opts metav1.UpdateOptions) (*apiv1.ClusterTestType, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, clusterTestType *apiv1.ClusterTestType, opts metav1.UpdateOptions) (*apiv1.ClusterTestType, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*apiv1.ClusterTestType, error) + List(ctx context.Context, opts metav1.ListOptions) (*apiv1.ClusterTestTypeList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *apiv1.ClusterTestType, err error) + Apply(ctx context.Context, clusterTestType *applyconfigurationapiv1.ClusterTestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *apiv1.ClusterTestType, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, clusterTestType *applyconfigurationapiv1.ClusterTestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *apiv1.ClusterTestType, err error) + GetScale(ctx context.Context, clusterTestTypeName string, options metav1.GetOptions) (*autoscalingv1.Scale, error) + UpdateScale(ctx context.Context, clusterTestTypeName string, scale *autoscalingv1.Scale, opts metav1.UpdateOptions) (*autoscalingv1.Scale, error) + + ClusterTestTypeExpansion +} + +// clusterTestTypes implements ClusterTestTypeInterface +type clusterTestTypes struct { + *gentype.ClientWithListAndApply[*apiv1.ClusterTestType, *apiv1.ClusterTestTypeList, *applyconfigurationapiv1.ClusterTestTypeApplyConfiguration] +} + +// newClusterTestTypes returns a ClusterTestTypes +func newClusterTestTypes(c *ExampleV1Client) *clusterTestTypes { + return &clusterTestTypes{ + gentype.NewClientWithListAndApply[*apiv1.ClusterTestType, *apiv1.ClusterTestTypeList, *applyconfigurationapiv1.ClusterTestTypeApplyConfiguration]( + "clustertesttypes", + c.RESTClient(), + scheme.ParameterCodec, + "", + func() *apiv1.ClusterTestType { return &apiv1.ClusterTestType{} }, + func() *apiv1.ClusterTestTypeList { return &apiv1.ClusterTestTypeList{} }), + } +} + +// GetScale takes name of the clusterTestType, and returns the corresponding autoscalingv1.Scale object, and an error if there is any. +func (c *clusterTestTypes) GetScale(ctx context.Context, clusterTestTypeName string, options metav1.GetOptions) (result *autoscalingv1.Scale, err error) { + result = &autoscalingv1.Scale{} + err = c.GetClient().Get(). + Resource("clustertesttypes"). + Name(clusterTestTypeName). + SubResource("scale"). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// UpdateScale takes the top resource name and the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *clusterTestTypes) UpdateScale(ctx context.Context, clusterTestTypeName string, scale *autoscalingv1.Scale, opts metav1.UpdateOptions) (result *autoscalingv1.Scale, err error) { + result = &autoscalingv1.Scale{} + err = c.GetClient().Put(). + Resource("clustertesttypes"). + Name(clusterTestTypeName). + SubResource("scale"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(scale). + Do(ctx). + Into(result) + return +} diff --git a/code-generator/examples/single/clientset/versioned/typed/api/v1/doc.go b/code-generator/examples/single/clientset/versioned/typed/api/v1/doc.go new file mode 100644 index 000000000..3af5d054f --- /dev/null +++ b/code-generator/examples/single/clientset/versioned/typed/api/v1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/code-generator/examples/single/clientset/versioned/typed/api/v1/fake/doc.go b/code-generator/examples/single/clientset/versioned/typed/api/v1/fake/doc.go new file mode 100644 index 000000000..16f443990 --- /dev/null +++ b/code-generator/examples/single/clientset/versioned/typed/api/v1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/code-generator/examples/single/clientset/versioned/typed/api/v1/fake/fake_api_client.go b/code-generator/examples/single/clientset/versioned/typed/api/v1/fake/fake_api_client.go new file mode 100644 index 000000000..905fbe027 --- /dev/null +++ b/code-generator/examples/single/clientset/versioned/typed/api/v1/fake/fake_api_client.go @@ -0,0 +1,44 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/single/clientset/versioned/typed/api/v1" +) + +type FakeExampleV1 struct { + *testing.Fake +} + +func (c *FakeExampleV1) ClusterTestTypes() v1.ClusterTestTypeInterface { + return &FakeClusterTestTypes{c} +} + +func (c *FakeExampleV1) TestTypes(namespace string) v1.TestTypeInterface { + return &FakeTestTypes{c, namespace} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeExampleV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/code-generator/examples/single/clientset/versioned/typed/api/v1/fake/fake_clustertesttype.go b/code-generator/examples/single/clientset/versioned/typed/api/v1/fake/fake_clustertesttype.go new file mode 100644 index 000000000..ad9c5e234 --- /dev/null +++ b/code-generator/examples/single/clientset/versioned/typed/api/v1/fake/fake_clustertesttype.go @@ -0,0 +1,209 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + json "encoding/json" + fmt "fmt" + + autoscalingv1 "k8s.io/api/autoscaling/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/single/api/v1" + apiv1 "k8s.io/code-generator/examples/single/applyconfiguration/api/v1" +) + +// FakeClusterTestTypes implements ClusterTestTypeInterface +type FakeClusterTestTypes struct { + Fake *FakeExampleV1 +} + +var clustertesttypesResource = v1.SchemeGroupVersion.WithResource("clustertesttypes") + +var clustertesttypesKind = v1.SchemeGroupVersion.WithKind("ClusterTestType") + +// Get takes name of the clusterTestType, and returns the corresponding clusterTestType object, and an error if there is any. +func (c *FakeClusterTestTypes) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootGetActionWithOptions(clustertesttypesResource, name, options), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// List takes label and field selectors, and returns the list of ClusterTestTypes that match those selectors. +func (c *FakeClusterTestTypes) List(ctx context.Context, opts metav1.ListOptions) (result *v1.ClusterTestTypeList, err error) { + emptyResult := &v1.ClusterTestTypeList{} + obj, err := c.Fake. + Invokes(testing.NewRootListActionWithOptions(clustertesttypesResource, clustertesttypesKind, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1.ClusterTestTypeList{ListMeta: obj.(*v1.ClusterTestTypeList).ListMeta} + for _, item := range obj.(*v1.ClusterTestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested clusterTestTypes. +func (c *FakeClusterTestTypes) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchActionWithOptions(clustertesttypesResource, opts)) +} + +// Create takes the representation of a clusterTestType and creates it. Returns the server's representation of the clusterTestType, and an error, if there is any. +func (c *FakeClusterTestTypes) Create(ctx context.Context, clusterTestType *v1.ClusterTestType, opts metav1.CreateOptions) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootCreateActionWithOptions(clustertesttypesResource, clusterTestType, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// Update takes the representation of a clusterTestType and updates it. Returns the server's representation of the clusterTestType, and an error, if there is any. +func (c *FakeClusterTestTypes) Update(ctx context.Context, clusterTestType *v1.ClusterTestType, opts metav1.UpdateOptions) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootUpdateActionWithOptions(clustertesttypesResource, clusterTestType, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeClusterTestTypes) UpdateStatus(ctx context.Context, clusterTestType *v1.ClusterTestType, opts metav1.UpdateOptions) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceActionWithOptions(clustertesttypesResource, "status", clusterTestType, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// Delete takes name of the clusterTestType and deletes it. Returns an error if one occurs. +func (c *FakeClusterTestTypes) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteActionWithOptions(clustertesttypesResource, name, opts), &v1.ClusterTestType{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeClusterTestTypes) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + action := testing.NewRootDeleteCollectionActionWithOptions(clustertesttypesResource, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1.ClusterTestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched clusterTestType. +func (c *FakeClusterTestTypes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.ClusterTestType, err error) { + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clustertesttypesResource, name, pt, data, opts, subresources...), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied clusterTestType. +func (c *FakeClusterTestTypes) Apply(ctx context.Context, clusterTestType *apiv1.ClusterTestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.ClusterTestType, err error) { + if clusterTestType == nil { + return nil, fmt.Errorf("clusterTestType provided to Apply must not be nil") + } + data, err := json.Marshal(clusterTestType) + if err != nil { + return nil, err + } + name := clusterTestType.Name + if name == nil { + return nil, fmt.Errorf("clusterTestType.Name must be provided to Apply") + } + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clustertesttypesResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeClusterTestTypes) ApplyStatus(ctx context.Context, clusterTestType *apiv1.ClusterTestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.ClusterTestType, err error) { + if clusterTestType == nil { + return nil, fmt.Errorf("clusterTestType provided to Apply must not be nil") + } + data, err := json.Marshal(clusterTestType) + if err != nil { + return nil, err + } + name := clusterTestType.Name + if name == nil { + return nil, fmt.Errorf("clusterTestType.Name must be provided to Apply") + } + emptyResult := &v1.ClusterTestType{} + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceActionWithOptions(clustertesttypesResource, *name, types.ApplyPatchType, data, opts.ToPatchOptions(), "status"), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*v1.ClusterTestType), err +} + +// GetScale takes name of the clusterTestType, and returns the corresponding scale object, and an error if there is any. +func (c *FakeClusterTestTypes) GetScale(ctx context.Context, clusterTestTypeName string, options metav1.GetOptions) (result *autoscalingv1.Scale, err error) { + emptyResult := &autoscalingv1.Scale{} + obj, err := c.Fake. + Invokes(testing.NewRootGetSubresourceActionWithOptions(clustertesttypesResource, "scale", clusterTestTypeName, options), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*autoscalingv1.Scale), err +} + +// UpdateScale takes the representation of a scale and updates it. Returns the server's representation of the scale, and an error, if there is any. +func (c *FakeClusterTestTypes) UpdateScale(ctx context.Context, clusterTestTypeName string, scale *autoscalingv1.Scale, opts metav1.UpdateOptions) (result *autoscalingv1.Scale, err error) { + emptyResult := &autoscalingv1.Scale{} + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceActionWithOptions(clustertesttypesResource, "scale", scale, opts), emptyResult) + if obj == nil { + return emptyResult, err + } + return obj.(*autoscalingv1.Scale), err +} diff --git a/code-generator/examples/single/clientset/versioned/typed/api/v1/fake/fake_testtype.go b/code-generator/examples/single/clientset/versioned/typed/api/v1/fake/fake_testtype.go new file mode 100644 index 000000000..2311573d6 --- /dev/null +++ b/code-generator/examples/single/clientset/versioned/typed/api/v1/fake/fake_testtype.go @@ -0,0 +1,197 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + json "encoding/json" + fmt "fmt" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1 "k8s.io/code-generator/examples/single/api/v1" + apiv1 "k8s.io/code-generator/examples/single/applyconfiguration/api/v1" +) + +// FakeTestTypes implements TestTypeInterface +type FakeTestTypes struct { + Fake *FakeExampleV1 + ns string +} + +var testtypesResource = v1.SchemeGroupVersion.WithResource("testtypes") + +var testtypesKind = v1.SchemeGroupVersion.WithKind("TestType") + +// Get takes name of the testType, and returns the corresponding testType object, and an error if there is any. +func (c *FakeTestTypes) Get(ctx context.Context, name string, options metav1.GetOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewGetActionWithOptions(testtypesResource, c.ns, name, options), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// List takes label and field selectors, and returns the list of TestTypes that match those selectors. +func (c *FakeTestTypes) List(ctx context.Context, opts metav1.ListOptions) (result *v1.TestTypeList, err error) { + emptyResult := &v1.TestTypeList{} + obj, err := c.Fake. + Invokes(testing.NewListActionWithOptions(testtypesResource, testtypesKind, c.ns, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1.TestTypeList{ListMeta: obj.(*v1.TestTypeList).ListMeta} + for _, item := range obj.(*v1.TestTypeList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested testTypes. +func (c *FakeTestTypes) Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchActionWithOptions(testtypesResource, c.ns, opts)) + +} + +// Create takes the representation of a testType and creates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Create(ctx context.Context, testType *v1.TestType, opts metav1.CreateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewCreateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Update takes the representation of a testType and updates it. Returns the server's representation of the testType, and an error, if there is any. +func (c *FakeTestTypes) Update(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateActionWithOptions(testtypesResource, c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTestTypes) UpdateStatus(ctx context.Context, testType *v1.TestType, opts metav1.UpdateOptions) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceActionWithOptions(testtypesResource, "status", c.ns, testType, opts), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Delete takes name of the testType and deletes it. Returns an error if one occurs. +func (c *FakeTestTypes) Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteActionWithOptions(testtypesResource, c.ns, name, opts), &v1.TestType{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTestTypes) DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error { + action := testing.NewDeleteCollectionActionWithOptions(testtypesResource, c.ns, opts, listOpts) + + _, err := c.Fake.Invokes(action, &v1.TestTypeList{}) + return err +} + +// Patch applies the patch and returns the patched testType. +func (c *FakeTestTypes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *v1.TestType, err error) { + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, name, pt, data, opts, subresources...), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// Apply takes the given apply declarative configuration, applies it and returns the applied testType. +func (c *FakeTestTypes) Apply(ctx context.Context, testType *apiv1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.TestType, err error) { + if testType == nil { + return nil, fmt.Errorf("testType provided to Apply must not be nil") + } + data, err := json.Marshal(testType) + if err != nil { + return nil, err + } + name := testType.Name + if name == nil { + return nil, fmt.Errorf("testType.Name must be provided to Apply") + } + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions()), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} + +// ApplyStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). +func (c *FakeTestTypes) ApplyStatus(ctx context.Context, testType *apiv1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *v1.TestType, err error) { + if testType == nil { + return nil, fmt.Errorf("testType provided to Apply must not be nil") + } + data, err := json.Marshal(testType) + if err != nil { + return nil, err + } + name := testType.Name + if name == nil { + return nil, fmt.Errorf("testType.Name must be provided to Apply") + } + emptyResult := &v1.TestType{} + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceActionWithOptions(testtypesResource, c.ns, *name, types.ApplyPatchType, data, opts.ToPatchOptions(), "status"), emptyResult) + + if obj == nil { + return emptyResult, err + } + return obj.(*v1.TestType), err +} diff --git a/code-generator/examples/single/clientset/versioned/typed/api/v1/generated_expansion.go b/code-generator/examples/single/clientset/versioned/typed/api/v1/generated_expansion.go new file mode 100644 index 000000000..3059734a9 --- /dev/null +++ b/code-generator/examples/single/clientset/versioned/typed/api/v1/generated_expansion.go @@ -0,0 +1,23 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +type ClusterTestTypeExpansion interface{} + +type TestTypeExpansion interface{} diff --git a/code-generator/examples/single/clientset/versioned/typed/api/v1/testtype.go b/code-generator/examples/single/clientset/versioned/typed/api/v1/testtype.go new file mode 100644 index 000000000..a747554b8 --- /dev/null +++ b/code-generator/examples/single/clientset/versioned/typed/api/v1/testtype.go @@ -0,0 +1,73 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + apiv1 "k8s.io/code-generator/examples/single/api/v1" + applyconfigurationapiv1 "k8s.io/code-generator/examples/single/applyconfiguration/api/v1" + scheme "k8s.io/code-generator/examples/single/clientset/versioned/scheme" +) + +// TestTypesGetter has a method to return a TestTypeInterface. +// A group's client should implement this interface. +type TestTypesGetter interface { + TestTypes(namespace string) TestTypeInterface +} + +// TestTypeInterface has methods to work with TestType resources. +type TestTypeInterface interface { + Create(ctx context.Context, testType *apiv1.TestType, opts metav1.CreateOptions) (*apiv1.TestType, error) + Update(ctx context.Context, testType *apiv1.TestType, opts metav1.UpdateOptions) (*apiv1.TestType, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, testType *apiv1.TestType, opts metav1.UpdateOptions) (*apiv1.TestType, error) + Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error + Get(ctx context.Context, name string, opts metav1.GetOptions) (*apiv1.TestType, error) + List(ctx context.Context, opts metav1.ListOptions) (*apiv1.TestTypeList, error) + Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *apiv1.TestType, err error) + Apply(ctx context.Context, testType *applyconfigurationapiv1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *apiv1.TestType, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, testType *applyconfigurationapiv1.TestTypeApplyConfiguration, opts metav1.ApplyOptions) (result *apiv1.TestType, err error) + TestTypeExpansion +} + +// testTypes implements TestTypeInterface +type testTypes struct { + *gentype.ClientWithListAndApply[*apiv1.TestType, *apiv1.TestTypeList, *applyconfigurationapiv1.TestTypeApplyConfiguration] +} + +// newTestTypes returns a TestTypes +func newTestTypes(c *ExampleV1Client, namespace string) *testTypes { + return &testTypes{ + gentype.NewClientWithListAndApply[*apiv1.TestType, *apiv1.TestTypeList, *applyconfigurationapiv1.TestTypeApplyConfiguration]( + "testtypes", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *apiv1.TestType { return &apiv1.TestType{} }, + func() *apiv1.TestTypeList { return &apiv1.TestTypeList{} }), + } +} diff --git a/code-generator/examples/single/informers/externalversions/api/interface.go b/code-generator/examples/single/informers/externalversions/api/interface.go new file mode 100644 index 000000000..633ba3d0d --- /dev/null +++ b/code-generator/examples/single/informers/externalversions/api/interface.go @@ -0,0 +1,46 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package api + +import ( + v1 "k8s.io/code-generator/examples/single/informers/externalversions/api/v1" + internalinterfaces "k8s.io/code-generator/examples/single/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/code-generator/examples/single/informers/externalversions/api/v1/clustertesttype.go b/code-generator/examples/single/informers/externalversions/api/v1/clustertesttype.go new file mode 100644 index 000000000..08a9947e8 --- /dev/null +++ b/code-generator/examples/single/informers/externalversions/api/v1/clustertesttype.go @@ -0,0 +1,89 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + singleapiv1 "k8s.io/code-generator/examples/single/api/v1" + versioned "k8s.io/code-generator/examples/single/clientset/versioned" + internalinterfaces "k8s.io/code-generator/examples/single/informers/externalversions/internalinterfaces" + apiv1 "k8s.io/code-generator/examples/single/listers/api/v1" +) + +// ClusterTestTypeInformer provides access to a shared informer and lister for +// ClusterTestTypes. +type ClusterTestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() apiv1.ClusterTestTypeLister +} + +type clusterTestTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewClusterTestTypeInformer constructs a new informer for ClusterTestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewClusterTestTypeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredClusterTestTypeInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredClusterTestTypeInformer constructs a new informer for ClusterTestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredClusterTestTypeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().ClusterTestTypes().List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().ClusterTestTypes().Watch(context.TODO(), options) + }, + }, + &singleapiv1.ClusterTestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *clusterTestTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredClusterTestTypeInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *clusterTestTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&singleapiv1.ClusterTestType{}, f.defaultInformer) +} + +func (f *clusterTestTypeInformer) Lister() apiv1.ClusterTestTypeLister { + return apiv1.NewClusterTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/code-generator/examples/single/informers/externalversions/api/v1/interface.go b/code-generator/examples/single/informers/externalversions/api/v1/interface.go new file mode 100644 index 000000000..442f04b95 --- /dev/null +++ b/code-generator/examples/single/informers/externalversions/api/v1/interface.go @@ -0,0 +1,52 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "k8s.io/code-generator/examples/single/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // ClusterTestTypes returns a ClusterTestTypeInformer. + ClusterTestTypes() ClusterTestTypeInformer + // TestTypes returns a TestTypeInformer. + TestTypes() TestTypeInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// ClusterTestTypes returns a ClusterTestTypeInformer. +func (v *version) ClusterTestTypes() ClusterTestTypeInformer { + return &clusterTestTypeInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + +// TestTypes returns a TestTypeInformer. +func (v *version) TestTypes() TestTypeInformer { + return &testTypeInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/code-generator/examples/single/informers/externalversions/api/v1/testtype.go b/code-generator/examples/single/informers/externalversions/api/v1/testtype.go new file mode 100644 index 000000000..1b07ff381 --- /dev/null +++ b/code-generator/examples/single/informers/externalversions/api/v1/testtype.go @@ -0,0 +1,90 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1 + +import ( + context "context" + time "time" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + singleapiv1 "k8s.io/code-generator/examples/single/api/v1" + versioned "k8s.io/code-generator/examples/single/clientset/versioned" + internalinterfaces "k8s.io/code-generator/examples/single/informers/externalversions/internalinterfaces" + apiv1 "k8s.io/code-generator/examples/single/listers/api/v1" +) + +// TestTypeInformer provides access to a shared informer and lister for +// TestTypes. +type TestTypeInformer interface { + Informer() cache.SharedIndexInformer + Lister() apiv1.TestTypeLister +} + +type testTypeInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTestTypeInformer constructs a new informer for TestType type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTestTypeInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().TestTypes(namespace).List(context.TODO(), options) + }, + WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExampleV1().TestTypes(namespace).Watch(context.TODO(), options) + }, + }, + &singleapiv1.TestType{}, + resyncPeriod, + indexers, + ) +} + +func (f *testTypeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTestTypeInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *testTypeInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&singleapiv1.TestType{}, f.defaultInformer) +} + +func (f *testTypeInformer) Lister() apiv1.TestTypeLister { + return apiv1.NewTestTypeLister(f.Informer().GetIndexer()) +} diff --git a/code-generator/examples/single/informers/externalversions/factory.go b/code-generator/examples/single/informers/externalversions/factory.go new file mode 100644 index 000000000..f282ac17b --- /dev/null +++ b/code-generator/examples/single/informers/externalversions/factory.go @@ -0,0 +1,262 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" + versioned "k8s.io/code-generator/examples/single/clientset/versioned" + api "k8s.io/code-generator/examples/single/informers/externalversions/api" + internalinterfaces "k8s.io/code-generator/examples/single/informers/externalversions/internalinterfaces" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + transform cache.TransformFunc + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool + // wg tracks how many goroutines were started. + wg sync.WaitGroup + // shuttingDown is true when Shutdown has been called. It may still be running + // because it needs to wait for goroutines. + shuttingDown bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// WithTransform sets a transform on all informers. +func WithTransform(transform cache.TransformFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.transform = transform + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + if f.shuttingDown { + return + } + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + f.wg.Add(1) + // We need a new variable in each loop iteration, + // otherwise the goroutine would use the loop variable + // and that keeps changing. + informer := informer + go func() { + defer f.wg.Done() + informer.Run(stopCh) + }() + f.startedInformers[informerType] = true + } + } +} + +func (f *sharedInformerFactory) Shutdown() { + f.lock.Lock() + f.shuttingDown = true + f.lock.Unlock() + + // Will return immediately if there is nothing to wait for. + f.wg.Wait() +} + +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + informer.SetTransform(f.transform) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +// +// It is typically used like this: +// +// ctx, cancel := context.Background() +// defer cancel() +// factory := NewSharedInformerFactory(client, resyncPeriod) +// defer factory.WaitForStop() // Returns immediately if nothing was started. +// genericInformer := factory.ForResource(resource) +// typedInformer := factory.SomeAPIGroup().V1().SomeType() +// factory.Start(ctx.Done()) // Start processing these informers. +// synced := factory.WaitForCacheSync(ctx.Done()) +// for v, ok := range synced { +// if !ok { +// fmt.Fprintf(os.Stderr, "caches failed to sync: %v", v) +// return +// } +// } +// +// // Creating informers can also be created after Start, but then +// // Start must be called again: +// anotherGenericInformer := factory.ForResource(resource) +// factory.Start(ctx.Done()) +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + + // Start initializes all requested informers. They are handled in goroutines + // which run until the stop channel gets closed. + // Warning: Start does not block. When run in a go-routine, it will race with a later WaitForCacheSync. + Start(stopCh <-chan struct{}) + + // Shutdown marks a factory as shutting down. At that point no new + // informers can be started anymore and Start will return without + // doing anything. + // + // In addition, Shutdown blocks until all goroutines have terminated. For that + // to happen, the close channel(s) that they were started with must be closed, + // either before Shutdown gets called or while it is waiting. + // + // Shutdown may be called multiple times, even concurrently. All such calls will + // block until all goroutines have terminated. + Shutdown() + + // WaitForCacheSync blocks until all started informers' caches were synced + // or the stop channel gets closed. + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + // ForResource gives generic access to a shared informer of the matching type. + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + + // InformerFor returns the SharedIndexInformer for obj using an internal + // client. + InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer + + Example() api.Interface +} + +func (f *sharedInformerFactory) Example() api.Interface { + return api.New(f, f.namespace, f.tweakListOptions) +} diff --git a/pkg/generated/informers/externalversions/generic.go b/code-generator/examples/single/informers/externalversions/generic.go similarity index 81% rename from pkg/generated/informers/externalversions/generic.go rename to code-generator/examples/single/informers/externalversions/generic.go index dbb89d316..59589221d 100644 --- a/pkg/generated/informers/externalversions/generic.go +++ b/code-generator/examples/single/informers/externalversions/generic.go @@ -23,7 +23,7 @@ import ( schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" - v1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1" + v1 "k8s.io/code-generator/examples/single/api/v1" ) // GenericInformer is type of SharedIndexInformer which will locate and delegate to other @@ -52,9 +52,11 @@ func (f *genericInformer) Lister() cache.GenericLister { // TODO extend this to unknown resources with a client pool func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { switch resource { - // Group=samplecontroller.k8s.io, Version=v1alpha1 - case v1alpha1.SchemeGroupVersion.WithResource("foos"): - return &genericInformer{resource: resource.GroupResource(), informer: f.Samplecontroller().V1alpha1().Foos().Informer()}, nil + // Group=example.crd.code-generator.k8s.io, Version=v1 + case v1.SchemeGroupVersion.WithResource("clustertesttypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Example().V1().ClusterTestTypes().Informer()}, nil + case v1.SchemeGroupVersion.WithResource("testtypes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Example().V1().TestTypes().Informer()}, nil } diff --git a/code-generator/examples/single/informers/externalversions/internalinterfaces/factory_interfaces.go b/code-generator/examples/single/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 000000000..20cb59b4b --- /dev/null +++ b/code-generator/examples/single/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,40 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" + versioned "k8s.io/code-generator/examples/single/clientset/versioned" +) + +// NewInformerFunc takes versioned.Interface and time.Duration to return a SharedIndexInformer. +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +// TweakListOptionsFunc is a function that transforms a v1.ListOptions. +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/code-generator/examples/single/listers/api/v1/clustertesttype.go b/code-generator/examples/single/listers/api/v1/clustertesttype.go new file mode 100644 index 000000000..a0ce0d3b7 --- /dev/null +++ b/code-generator/examples/single/listers/api/v1/clustertesttype.go @@ -0,0 +1,48 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" + apiv1 "k8s.io/code-generator/examples/single/api/v1" +) + +// ClusterTestTypeLister helps list ClusterTestTypes. +// All objects returned here must be treated as read-only. +type ClusterTestTypeLister interface { + // List lists all ClusterTestTypes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1.ClusterTestType, err error) + // Get retrieves the ClusterTestType from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*apiv1.ClusterTestType, error) + ClusterTestTypeListerExpansion +} + +// clusterTestTypeLister implements the ClusterTestTypeLister interface. +type clusterTestTypeLister struct { + listers.ResourceIndexer[*apiv1.ClusterTestType] +} + +// NewClusterTestTypeLister returns a new ClusterTestTypeLister. +func NewClusterTestTypeLister(indexer cache.Indexer) ClusterTestTypeLister { + return &clusterTestTypeLister{listers.New[*apiv1.ClusterTestType](indexer, apiv1.Resource("clustertesttype"))} +} diff --git a/code-generator/examples/single/listers/api/v1/expansion_generated.go b/code-generator/examples/single/listers/api/v1/expansion_generated.go new file mode 100644 index 000000000..2681a29f4 --- /dev/null +++ b/code-generator/examples/single/listers/api/v1/expansion_generated.go @@ -0,0 +1,31 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +// ClusterTestTypeListerExpansion allows custom methods to be added to +// ClusterTestTypeLister. +type ClusterTestTypeListerExpansion interface{} + +// TestTypeListerExpansion allows custom methods to be added to +// TestTypeLister. +type TestTypeListerExpansion interface{} + +// TestTypeNamespaceListerExpansion allows custom methods to be added to +// TestTypeNamespaceLister. +type TestTypeNamespaceListerExpansion interface{} diff --git a/code-generator/examples/single/listers/api/v1/testtype.go b/code-generator/examples/single/listers/api/v1/testtype.go new file mode 100644 index 000000000..37e13bfa9 --- /dev/null +++ b/code-generator/examples/single/listers/api/v1/testtype.go @@ -0,0 +1,70 @@ +/* +Copyright The Kubernetes 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1 + +import ( + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" + apiv1 "k8s.io/code-generator/examples/single/api/v1" +) + +// TestTypeLister helps list TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeLister interface { + // List lists all TestTypes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1.TestType, err error) + // TestTypes returns an object that can list and get TestTypes. + TestTypes(namespace string) TestTypeNamespaceLister + TestTypeListerExpansion +} + +// testTypeLister implements the TestTypeLister interface. +type testTypeLister struct { + listers.ResourceIndexer[*apiv1.TestType] +} + +// NewTestTypeLister returns a new TestTypeLister. +func NewTestTypeLister(indexer cache.Indexer) TestTypeLister { + return &testTypeLister{listers.New[*apiv1.TestType](indexer, apiv1.Resource("testtype"))} +} + +// TestTypes returns an object that can list and get TestTypes. +func (s *testTypeLister) TestTypes(namespace string) TestTypeNamespaceLister { + return testTypeNamespaceLister{listers.NewNamespaced[*apiv1.TestType](s.ResourceIndexer, namespace)} +} + +// TestTypeNamespaceLister helps list and get TestTypes. +// All objects returned here must be treated as read-only. +type TestTypeNamespaceLister interface { + // List lists all TestTypes in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apiv1.TestType, err error) + // Get retrieves the TestType from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*apiv1.TestType, error) + TestTypeNamespaceListerExpansion +} + +// testTypeNamespaceLister implements the TestTypeNamespaceLister +// interface. +type testTypeNamespaceLister struct { + listers.ResourceIndexer[*apiv1.TestType] +} diff --git a/code-generator/generate-groups.sh b/code-generator/generate-groups.sh new file mode 100755 index 000000000..65b0abda5 --- /dev/null +++ b/code-generator/generate-groups.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# Copyright 2017 The Kubernetes 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. + +echo "ERROR: $(basename "$0") has been removed." +echo "ERROR: Please use k8s.io/code-generator/kube_codegen.sh instead." +echo +exit 1 diff --git a/code-generator/generate-internal-groups.sh b/code-generator/generate-internal-groups.sh new file mode 100755 index 000000000..65b0abda5 --- /dev/null +++ b/code-generator/generate-internal-groups.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# Copyright 2017 The Kubernetes 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. + +echo "ERROR: $(basename "$0") has been removed." +echo "ERROR: Please use k8s.io/code-generator/kube_codegen.sh instead." +echo +exit 1 diff --git a/code-generator/go.mod b/code-generator/go.mod new file mode 100644 index 000000000..4ecb5b96e --- /dev/null +++ b/code-generator/go.mod @@ -0,0 +1,45 @@ +// This is a generated file. Do not edit directly. + +module k8s.io/code-generator + +go 1.23.0 + +godebug default=go1.23 + +require ( + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc + github.com/gogo/protobuf v1.3.2 + github.com/google/gnostic-models v0.6.8 + github.com/google/go-cmp v0.6.0 + github.com/google/gofuzz v1.2.0 + github.com/spf13/pflag v1.0.5 + golang.org/x/text v0.17.0 + gopkg.in/yaml.v2 v2.4.0 + k8s.io/apimachinery v0.0.0-20240912032824-4e174c5e3655 + k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 + k8s.io/klog/v2 v2.130.1 + k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 +) + +require ( + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/x448/float16 v0.8.4 // indirect + golang.org/x/mod v0.20.0 // indirect + golang.org/x/sync v0.8.0 // indirect + golang.org/x/tools v0.24.0 // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect +) diff --git a/code-generator/go.sum b/code-generator/go.sum new file mode 100644 index 000000000..a4260b8c2 --- /dev/null +++ b/code-generator/go.sum @@ -0,0 +1,145 @@ +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k= +github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/apimachinery v0.0.0-20240912032824-4e174c5e3655 h1:hIG8XQN1zNsQb1PU+QnTn/sQgX/lch8BICCtqS1mD5E= +k8s.io/apimachinery v0.0.0-20240912032824-4e174c5e3655/go.mod h1:5rKPDwwN9qm//xASFCZ83nyYEanHxxhc7pZ8AC4lukY= +k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 h1:si3PfKm8dDYxgfbeA6orqrtLkvvIeH8UqffFJDl0bz4= +k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2 h1:GKE9U8BH16uynoxQii0auTjmmmuZ3O0LFMN6S0lPPhI= +k8s.io/kube-openapi v0.0.0-20240827152857-f7e401e7b4c2/go.mod h1:coRQXBK9NxO98XUv3ZD6AK3xzHCxV6+b7lrquKwaKzA= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/code-generator/kube_codegen.sh b/code-generator/kube_codegen.sh new file mode 100755 index 000000000..f57c52cae --- /dev/null +++ b/code-generator/kube_codegen.sh @@ -0,0 +1,759 @@ +#!/usr/bin/env bash + +# Copyright 2023 The Kubernetes 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. + +# This presents several functions for packages which want to use kubernetes +# code-generation tools. + +# These functions insist that your input IDL (commented go) files be located in +# go packages following the pattern $input_pkg_root/$something_sans_slash/$api_version . +# Those $something_sans_slash will be propagated into the output directory structure. + +set -o errexit +set -o nounset +set -o pipefail + +KUBE_CODEGEN_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)" + +function kube::codegen::internal::findz() { + # We use `find` rather than `git ls-files` because sometimes external + # projects use this across repos. This is an imperfect wrapper of find, + # but good enough for this script. + find "$@" -print0 +} + +function kube::codegen::internal::grep() { + # We use `grep` rather than `git grep` because sometimes external projects + # use this across repos. + grep "$@" \ + --exclude-dir .git \ + --exclude-dir _output \ + --exclude-dir vendor +} + +# Generate tagged helper code: conversions, deepcopy, and defaults +# +# USAGE: kube::codegen::gen_helpers [FLAGS] +# +# +# The root directory under which to search for Go files which request code to +# be generated. This must be a local path, not a Go package. +# +# See note at the top about package structure below that. +# +# FLAGS: +# +# --boilerplate +# An optional override for the header file to insert into generated files. +# +# --extra-peer-dir +# An optional list (this flag may be specified multiple times) of "extra" +# directories to consider during conversion generation. +# +function kube::codegen::gen_helpers() { + local in_dir="" + local boilerplate="${KUBE_CODEGEN_ROOT}/hack/boilerplate.go.txt" + local v="${KUBE_VERBOSE:-0}" + local extra_peers=() + + while [ "$#" -gt 0 ]; do + case "$1" in + "--boilerplate") + boilerplate="$2" + shift 2 + ;; + "--extra-peer-dir") + extra_peers+=("$2") + shift 2 + ;; + *) + if [[ "$1" =~ ^-- ]]; then + echo "unknown argument: $1" >&2 + return 1 + fi + if [ -n "$in_dir" ]; then + echo "too many arguments: $1 (already have $in_dir)" >&2 + return 1 + fi + in_dir="$1" + shift + ;; + esac + done + + if [ -z "${in_dir}" ]; then + echo "input-dir argument is required" >&2 + return 1 + fi + + ( + # To support running this from anywhere, first cd into this directory, + # and then install with forced module mode on and fully qualified name. + cd "${KUBE_CODEGEN_ROOT}" + BINS=( + conversion-gen + deepcopy-gen + defaulter-gen + ) + # shellcheck disable=2046 # printf word-splitting is intentional + GO111MODULE=on go install $(printf "k8s.io/code-generator/cmd/%s " "${BINS[@]}") + ) + # Go installs in $GOBIN if defined, and $GOPATH/bin otherwise + gobin="${GOBIN:-$(go env GOPATH)/bin}" + + # Deepcopy + # + local input_pkgs=() + while read -r dir; do + pkg="$(cd "${dir}" && GO111MODULE=on go list -find .)" + input_pkgs+=("${pkg}") + done < <( + ( kube::codegen::internal::grep -l --null \ + -e '^\s*//\s*+k8s:deepcopy-gen=' \ + -r "${in_dir}" \ + --include '*.go' \ + || true \ + ) | while read -r -d $'\0' F; do dirname "${F}"; done \ + | LC_ALL=C sort -u + ) + + if [ "${#input_pkgs[@]}" != 0 ]; then + echo "Generating deepcopy code for ${#input_pkgs[@]} targets" + + kube::codegen::internal::findz \ + "${in_dir}" \ + -type f \ + -name zz_generated.deepcopy.go \ + | xargs -0 rm -f + + "${gobin}/deepcopy-gen" \ + -v "${v}" \ + --output-file zz_generated.deepcopy.go \ + --go-header-file "${boilerplate}" \ + "${input_pkgs[@]}" + fi + + # Defaults + # + local input_pkgs=() + while read -r dir; do + pkg="$(cd "${dir}" && GO111MODULE=on go list -find .)" + input_pkgs+=("${pkg}") + done < <( + ( kube::codegen::internal::grep -l --null \ + -e '^\s*//\s*+k8s:defaulter-gen=' \ + -r "${in_dir}" \ + --include '*.go' \ + || true \ + ) | while read -r -d $'\0' F; do dirname "${F}"; done \ + | LC_ALL=C sort -u + ) + + if [ "${#input_pkgs[@]}" != 0 ]; then + echo "Generating defaulter code for ${#input_pkgs[@]} targets" + + kube::codegen::internal::findz \ + "${in_dir}" \ + -type f \ + -name zz_generated.defaults.go \ + | xargs -0 rm -f + + "${gobin}/defaulter-gen" \ + -v "${v}" \ + --output-file zz_generated.defaults.go \ + --go-header-file "${boilerplate}" \ + "${input_pkgs[@]}" + fi + + # Conversions + # + local input_pkgs=() + while read -r dir; do + pkg="$(cd "${dir}" && GO111MODULE=on go list -find .)" + input_pkgs+=("${pkg}") + done < <( + ( kube::codegen::internal::grep -l --null \ + -e '^\s*//\s*+k8s:conversion-gen=' \ + -r "${in_dir}" \ + --include '*.go' \ + || true \ + ) | while read -r -d $'\0' F; do dirname "${F}"; done \ + | LC_ALL=C sort -u + ) + + if [ "${#input_pkgs[@]}" != 0 ]; then + echo "Generating conversion code for ${#input_pkgs[@]} targets" + + kube::codegen::internal::findz \ + "${in_dir}" \ + -type f \ + -name zz_generated.conversion.go \ + | xargs -0 rm -f + + local extra_peer_args=() + for arg in "${extra_peers[@]:+"${extra_peers[@]}"}"; do + extra_peer_args+=("--extra-peer-dirs" "$arg") + done + "${gobin}/conversion-gen" \ + -v "${v}" \ + --output-file zz_generated.conversion.go \ + --go-header-file "${boilerplate}" \ + "${extra_peer_args[@]:+"${extra_peer_args[@]}"}" \ + "${input_pkgs[@]}" + fi +} + +# Generate openapi code +# +# USAGE: kube::codegen::gen_openapi [FLAGS] +# +# +# The root directory under which to search for Go files which request openapi +# to be generated. This must be a local path, not a Go package. +# +# See note at the top about package structure below that. +# +# FLAGS: +# +# --output-dir +# The directory into which to emit code. +# +# --output-pkg +# The Go package path (import path) of the --output-dir. +# +# --extra-pkgs +# An optional list of additional packages to be imported during openapi +# generation. The argument must be Go package syntax, e.g. +# "k8s.io/foo/bar". It may be a single value or a comma-delimited list. +# This flag may be repeated. +# +# --report-filename +# An optional path at which to write an API violations report. "-" means +# stdout. +# +# --update-report +# If specified, update the report file in place, rather than diffing it. +# +# --boilerplate +# An optional override for the header file to insert into generated files. +# +function kube::codegen::gen_openapi() { + local in_dir="" + local out_dir="" + local out_pkg="" + local extra_pkgs=() + local report="/dev/null" + local update_report="" + local boilerplate="${KUBE_CODEGEN_ROOT}/hack/boilerplate.go.txt" + local v="${KUBE_VERBOSE:-0}" + + while [ "$#" -gt 0 ]; do + case "$1" in + "--output-dir") + out_dir="$2" + shift 2 + ;; + "--output-pkg") + out_pkg="$2" + shift 2 + ;; + "--extra-pkgs") + extra_pkgs+=("$2") + shift 2 + ;; + "--report-filename") + report="$2" + shift 2 + ;; + "--update-report") + update_report="true" + shift + ;; + "--boilerplate") + boilerplate="$2" + shift 2 + ;; + *) + if [[ "$1" =~ ^-- ]]; then + echo "unknown argument: $1" >&2 + return 1 + fi + if [ -n "$in_dir" ]; then + echo "too many arguments: $1 (already have $in_dir)" >&2 + return 1 + fi + in_dir="$1" + shift + ;; + esac + done + + if [ -z "${in_dir}" ]; then + echo "input-dir argument is required" >&2 + return 1 + fi + if [ -z "${out_dir}" ]; then + echo "--output-dir is required" >&2 + return 1 + fi + if [ -z "${out_pkg}" ]; then + echo "--output-pkg is required" >&2 + return 1 + fi + + local new_report + new_report="$(mktemp -t "$(basename "$0").api_violations.XXXXXX")" + if [ -n "${update_report}" ]; then + new_report="${report}" + fi + + ( + # To support running this from anywhere, first cd into this directory, + # and then install with forced module mode on and fully qualified name. + cd "${KUBE_CODEGEN_ROOT}" + BINS=( + openapi-gen + ) + # shellcheck disable=2046 # printf word-splitting is intentional + GO111MODULE=on go install $(printf "k8s.io/kube-openapi/cmd/%s " "${BINS[@]}") + ) + # Go installs in $GOBIN if defined, and $GOPATH/bin otherwise + gobin="${GOBIN:-$(go env GOPATH)/bin}" + + local input_pkgs=( "${extra_pkgs[@]:+"${extra_pkgs[@]}"}") + while read -r dir; do + pkg="$(cd "${dir}" && GO111MODULE=on go list -find .)" + input_pkgs+=("${pkg}") + done < <( + ( kube::codegen::internal::grep -l --null \ + -e '^\s*//\s*+k8s:openapi-gen=' \ + -r "${in_dir}" \ + --include '*.go' \ + || true \ + ) | while read -r -d $'\0' F; do dirname "${F}"; done \ + | LC_ALL=C sort -u + ) + + if [ "${#input_pkgs[@]}" != 0 ]; then + echo "Generating openapi code for ${#input_pkgs[@]} targets" + + kube::codegen::internal::findz \ + "${in_dir}" \ + -type f \ + -name zz_generated.openapi.go \ + | xargs -0 rm -f + + "${gobin}/openapi-gen" \ + -v "${v}" \ + --output-file zz_generated.openapi.go \ + --go-header-file "${boilerplate}" \ + --output-dir "${out_dir}" \ + --output-pkg "${out_pkg}" \ + --report-filename "${new_report}" \ + "k8s.io/apimachinery/pkg/apis/meta/v1" \ + "k8s.io/apimachinery/pkg/runtime" \ + "k8s.io/apimachinery/pkg/version" \ + "${input_pkgs[@]}" + fi + + touch "${report}" # in case it doesn't exist yet + if ! diff -u "${report}" "${new_report}"; then + echo -e "ERROR:" + echo -e "\tAPI rule check failed for ${report}: new reported violations" + echo -e "\tPlease read api/api-rules/README.md" + return 1 + fi +} + +# Generate client code +# +# USAGE: kube::codegen::gen_client [FLAGS] +# +# +# The root package under which to search for Go files which request clients +# to be generated. This must be a local path, not a Go package. +# +# See note at the top about package structure below that. +# +# FLAGS: +# --one-input-api +# A specific API (a directory) under the input-dir for which to generate a +# client. If this is not set, clients for all APIs under the input-dir +# will be generated (under the --output-pkg). +# +# --output-dir +# The root directory under which to emit code. Each aspect of client +# generation will make one or more subdirectories. +# +# --output-pkg +# The Go package path (import path) of the --output-dir. Each aspect of +# client generation will make one or more sub-packages. +# +# --boilerplate +# An optional override for the header file to insert into generated files. +# +# --clientset-name +# An optional override for the leaf name of the generated "clientset" directory. +# +# --versioned-name +# An optional override for the leaf name of the generated +# "/versioned" directory. +# +# --with-applyconfig +# Enables generation of applyconfiguration files. +# +# --applyconfig-name +# An optional override for the leaf name of the generated "applyconfiguration" directory. +# +# --applyconfig-externals +# An optional list of comma separated external apply configurations locations +# in .: form. +# +# --with-watch +# Enables generation of listers and informers for APIs which support WATCH. +# +# --listers-name +# An optional override for the leaf name of the generated "listers" directory. +# +# --informers-name +# An optional override for the leaf name of the generated "informers" directory. +# +# --plural-exceptions +# An optional list of comma separated plural exception definitions in Type:PluralizedType form. +# +function kube::codegen::gen_client() { + local in_dir="" + local one_input_api="" + local out_dir="" + local out_pkg="" + local clientset_subdir="clientset" + local clientset_versioned_name="versioned" + local applyconfig="false" + local applyconfig_subdir="applyconfiguration" + local applyconfig_external="" + local applyconfig_openapi_schema="" + local watchable="false" + local listers_subdir="listers" + local informers_subdir="informers" + local boilerplate="${KUBE_CODEGEN_ROOT}/hack/boilerplate.go.txt" + local plural_exceptions="" + local v="${KUBE_VERBOSE:-0}" + + while [ "$#" -gt 0 ]; do + case "$1" in + "--one-input-api") + one_input_api="/$2" + shift 2 + ;; + "--output-dir") + out_dir="$2" + shift 2 + ;; + "--output-pkg") + out_pkg="$2" + shift 2 + ;; + "--boilerplate") + boilerplate="$2" + shift 2 + ;; + "--clientset-name") + clientset_subdir="$2" + shift 2 + ;; + "--versioned-name") + clientset_versioned_name="$2" + shift 2 + ;; + "--with-applyconfig") + applyconfig="true" + shift + ;; + "--applyconfig-name") + applyconfig_subdir="$2" + shift 2 + ;; + "--applyconfig-externals") + applyconfig_external="$2" + shift 2 + ;; + "--applyconfig-openapi-schema") + applyconfig_openapi_schema="$2" + shift 2 + ;; + "--with-watch") + watchable="true" + shift + ;; + "--listers-name") + listers_subdir="$2" + shift 2 + ;; + "--informers-name") + informers_subdir="$2" + shift 2 + ;; + "--plural-exceptions") + plural_exceptions="$2" + shift 2 + ;; + *) + if [[ "$1" =~ ^-- ]]; then + echo "unknown argument: $1" >&2 + return 1 + fi + if [ -n "$in_dir" ]; then + echo "too many arguments: $1 (already have $in_dir)" >&2 + return 1 + fi + in_dir="$1" + shift + ;; + esac + done + + if [ -z "${in_dir}" ]; then + echo "input-dir argument is required" >&2 + return 1 + fi + if [ -z "${out_dir}" ]; then + echo "--output-dir is required" >&2 + return 1 + fi + if [ -z "${out_pkg}" ]; then + echo "--output-pkg is required" >&2 + fi + + mkdir -p "${out_dir}" + + ( + # To support running this from anywhere, first cd into this directory, + # and then install with forced module mode on and fully qualified name. + cd "${KUBE_CODEGEN_ROOT}" + BINS=( + applyconfiguration-gen + client-gen + informer-gen + lister-gen + ) + # shellcheck disable=2046 # printf word-splitting is intentional + GO111MODULE=on go install $(printf "k8s.io/code-generator/cmd/%s " "${BINS[@]}") + ) + # Go installs in $GOBIN if defined, and $GOPATH/bin otherwise + gobin="${GOBIN:-$(go env GOPATH)/bin}" + + local group_versions=() + local input_pkgs=() + while read -r dir; do + pkg="$(cd "${dir}" && GO111MODULE=on go list -find .)" + leaf="$(basename "${dir}")" + if grep -E -q '^v[0-9]+((alpha|beta)[0-9]+)?$' <<< "${leaf}"; then + input_pkgs+=("${pkg}") + + dir2="$(dirname "${dir}")" + leaf2="$(basename "${dir2}")" + group_versions+=("${leaf2}/${leaf}") + fi + done < <( + ( kube::codegen::internal::grep -l --null \ + -e '^\s*//\s*+genclient' \ + -r "${in_dir}${one_input_api}" \ + --include '*.go' \ + || true \ + ) | while read -r -d $'\0' F; do dirname "${F}"; done \ + | LC_ALL=C sort -u + ) + + if [ "${#group_versions[@]}" == 0 ]; then + return 0 + fi + + applyconfig_pkg="" # set this for later use, iff enabled + if [ "${applyconfig}" == "true" ]; then + applyconfig_pkg="${out_pkg}/${applyconfig_subdir}" + + echo "Generating applyconfig code for ${#input_pkgs[@]} targets" + + ( kube::codegen::internal::grep -l --null \ + -e '^// Code generated by applyconfiguration-gen. DO NOT EDIT.$' \ + -r "${out_dir}/${applyconfig_subdir}" \ + --include '*.go' \ + || true \ + ) | xargs -0 rm -f + + "${gobin}/applyconfiguration-gen" \ + -v "${v}" \ + --go-header-file "${boilerplate}" \ + --output-dir "${out_dir}/${applyconfig_subdir}" \ + --output-pkg "${applyconfig_pkg}" \ + --external-applyconfigurations "${applyconfig_external}" \ + --openapi-schema "${applyconfig_openapi_schema}" \ + "${input_pkgs[@]}" + fi + + echo "Generating client code for ${#group_versions[@]} targets" + + ( kube::codegen::internal::grep -l --null \ + -e '^// Code generated by client-gen. DO NOT EDIT.$' \ + -r "${out_dir}/${clientset_subdir}" \ + --include '*.go' \ + || true \ + ) | xargs -0 rm -f + + local inputs=() + for arg in "${group_versions[@]}"; do + inputs+=("--input" "$arg") + done + "${gobin}/client-gen" \ + -v "${v}" \ + --go-header-file "${boilerplate}" \ + --output-dir "${out_dir}/${clientset_subdir}" \ + --output-pkg "${out_pkg}/${clientset_subdir}" \ + --clientset-name "${clientset_versioned_name}" \ + --apply-configuration-package "${applyconfig_pkg}" \ + --input-base "$(cd "${in_dir}" && pwd -P)" `# must be absolute path or Go import path"` \ + --plural-exceptions "${plural_exceptions}" \ + "${inputs[@]}" + + if [ "${watchable}" == "true" ]; then + echo "Generating lister code for ${#input_pkgs[@]} targets" + + ( kube::codegen::internal::grep -l --null \ + -e '^// Code generated by lister-gen. DO NOT EDIT.$' \ + -r "${out_dir}/${listers_subdir}" \ + --include '*.go' \ + || true \ + ) | xargs -0 rm -f + + "${gobin}/lister-gen" \ + -v "${v}" \ + --go-header-file "${boilerplate}" \ + --output-dir "${out_dir}/${listers_subdir}" \ + --output-pkg "${out_pkg}/${listers_subdir}" \ + --plural-exceptions "${plural_exceptions}" \ + "${input_pkgs[@]}" + + echo "Generating informer code for ${#input_pkgs[@]} targets" + + ( kube::codegen::internal::grep -l --null \ + -e '^// Code generated by informer-gen. DO NOT EDIT.$' \ + -r "${out_dir}/${informers_subdir}" \ + --include '*.go' \ + || true \ + ) | xargs -0 rm -f + + "${gobin}/informer-gen" \ + -v "${v}" \ + --go-header-file "${boilerplate}" \ + --output-dir "${out_dir}/${informers_subdir}" \ + --output-pkg "${out_pkg}/${informers_subdir}" \ + --versioned-clientset-package "${out_pkg}/${clientset_subdir}/${clientset_versioned_name}" \ + --listers-package "${out_pkg}/${listers_subdir}" \ + --plural-exceptions "${plural_exceptions}" \ + "${input_pkgs[@]}" + fi +} + +# Generate register code +# +# USAGE: kube::codegen::gen_register [FLAGS] +# +# +# The root directory under which to search for Go files which request code to +# be generated. This must be a local path, not a Go package. +# +# See note at the top about package structure below that. +# +# FLAGS: +# +# --boilerplate +# An optional override for the header file to insert into generated files. +# +function kube::codegen::gen_register() { + local in_dir="" + local boilerplate="${KUBE_CODEGEN_ROOT}/hack/boilerplate.go.txt" + local v="${KUBE_VERBOSE:-0}" + + while [ "$#" -gt 0 ]; do + case "$1" in + "--boilerplate") + boilerplate="$2" + shift 2 + ;; + *) + if [[ "$1" =~ ^-- ]]; then + echo "unknown argument: $1" >&2 + return 1 + fi + if [ -n "$in_dir" ]; then + echo "too many arguments: $1 (already have $in_dir)" >&2 + return 1 + fi + in_dir="$1" + shift + ;; + esac + done + + if [ -z "${in_dir}" ]; then + echo "input-dir argument is required" >&2 + return 1 + fi + + ( + # To support running this from anywhere, first cd into this directory, + # and then install with forced module mode on and fully qualified name. + cd "${KUBE_CODEGEN_ROOT}" + BINS=( + register-gen + ) + # shellcheck disable=2046 # printf word-splitting is intentional + GO111MODULE=on go install $(printf "k8s.io/code-generator/cmd/%s " "${BINS[@]}") + ) + # Go installs in $GOBIN if defined, and $GOPATH/bin otherwise + gobin="${GOBIN:-$(go env GOPATH)/bin}" + + # Register + # + local input_pkgs=() + while read -r dir; do + pkg="$(cd "${dir}" && GO111MODULE=on go list -find .)" + input_pkgs+=("${pkg}") + done < <( + ( kube::codegen::internal::grep -l --null \ + -e '^\s*//\s*+groupName' \ + -r "${in_dir}" \ + --include '*.go' \ + || true \ + ) | while read -r -d $'\0' F; do dirname "${F}"; done \ + | LC_ALL=C sort -u + ) + + if [ "${#input_pkgs[@]}" != 0 ]; then + echo "Generating register code for ${#input_pkgs[@]} targets" + + kube::codegen::internal::findz \ + "${in_dir}" \ + -type f \ + -name zz_generated.register.go \ + | xargs -0 rm -f + + "${gobin}/register-gen" \ + -v "${v}" \ + --output-file zz_generated.register.go \ + --go-header-file "${boilerplate}" \ + "${input_pkgs[@]}" + fi +} diff --git a/code-generator/pkg/namer/tag-override.go b/code-generator/pkg/namer/tag-override.go new file mode 100644 index 000000000..59ee489f0 --- /dev/null +++ b/code-generator/pkg/namer/tag-override.go @@ -0,0 +1,59 @@ +/* +Copyright 2016 The Kubernetes 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 namer + +import ( + "k8s.io/gengo/v2" + "k8s.io/gengo/v2/namer" + "k8s.io/gengo/v2/types" +) + +// TagOverrideNamer is a namer which pulls names from a given tag, if specified, +// and otherwise falls back to a different namer. +type TagOverrideNamer struct { + tagName string + fallback namer.Namer +} + +// Name returns the tag value if it exists. It no tag was found the fallback namer will be used +func (n *TagOverrideNamer) Name(t *types.Type) string { + if nameOverride := extractTag(n.tagName, append(t.SecondClosestCommentLines, t.CommentLines...)); nameOverride != "" { + return nameOverride + } + + return n.fallback.Name(t) +} + +// NewTagOverrideNamer creates a namer.Namer which uses the contents of the given tag as +// the name, or falls back to another Namer if the tag is not present. +func NewTagOverrideNamer(tagName string, fallback namer.Namer) namer.Namer { + return &TagOverrideNamer{ + tagName: tagName, + fallback: fallback, + } +} + +// extractTag gets the comment-tags for the key. If the tag did not exist, it +// returns the empty string. +func extractTag(key string, lines []string) string { + val, present := gengo.ExtractCommentTags("+", lines)[key] + if !present || len(val) < 1 { + return "" + } + + return val[0] +} diff --git a/code-generator/pkg/util/plural_exceptions.go b/code-generator/pkg/util/plural_exceptions.go new file mode 100644 index 000000000..73c648d5b --- /dev/null +++ b/code-generator/pkg/util/plural_exceptions.go @@ -0,0 +1,37 @@ +/* +Copyright 2017 The Kubernetes 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 util + +import ( + "fmt" + "strings" +) + +// PluralExceptionListToMapOrDie converts the list in "Type:PluralType" to map[string]string. +// This is used for pluralizer. +// If the format is wrong, this function will panic. +func PluralExceptionListToMapOrDie(pluralExceptions []string) map[string]string { + pluralExceptionMap := make(map[string]string, len(pluralExceptions)) + for i := range pluralExceptions { + parts := strings.Split(pluralExceptions[i], ":") + if len(parts) != 2 { + panic(fmt.Sprintf("invalid plural exception definition: %s", pluralExceptions[i])) + } + pluralExceptionMap[parts[0]] = parts[1] + } + return pluralExceptionMap +} diff --git a/code-generator/third_party/forked/golang/LICENSE b/code-generator/third_party/forked/golang/LICENSE new file mode 100644 index 000000000..6a66aea5e --- /dev/null +++ b/code-generator/third_party/forked/golang/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/code-generator/third_party/forked/golang/PATENTS b/code-generator/third_party/forked/golang/PATENTS new file mode 100644 index 000000000..733099041 --- /dev/null +++ b/code-generator/third_party/forked/golang/PATENTS @@ -0,0 +1,22 @@ +Additional IP Rights Grant (Patents) + +"This implementation" means the copyrightable works distributed by +Google as part of the Go project. + +Google hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) +patent license to make, have made, use, offer to sell, sell, import, +transfer and otherwise run, modify and propagate the contents of this +implementation of Go, where such license applies only to those patent +claims, both currently owned or controlled by Google and acquired in +the future, licensable by Google that are necessarily infringed by this +implementation of Go. This grant does not include claims that would be +infringed only as a consequence of further modification of this +implementation. If you or your agent or exclusive licensee institute or +order or agree to the institution of patent litigation against any +entity (including a cross-claim or counterclaim in a lawsuit) alleging +that this implementation of Go or any code incorporated within this +implementation of Go constitutes direct or contributory patent +infringement, or inducement of patent infringement, then any patent +rights granted to you under this License for this implementation of Go +shall terminate as of the date such litigation is filed. diff --git a/code-generator/third_party/forked/golang/reflect/type.go b/code-generator/third_party/forked/golang/reflect/type.go new file mode 100644 index 000000000..67957ee33 --- /dev/null +++ b/code-generator/third_party/forked/golang/reflect/type.go @@ -0,0 +1,91 @@ +//This package is copied from Go library reflect/type.go. +//The struct tag library provides no way to extract the list of struct tags, only +//a specific tag +package reflect + +import ( + "fmt" + + "strconv" + "strings" +) + +type StructTag struct { + Name string + Value string +} + +func (t StructTag) String() string { + return fmt.Sprintf("%s:%q", t.Name, t.Value) +} + +type StructTags []StructTag + +func (tags StructTags) String() string { + s := make([]string, 0, len(tags)) + for _, tag := range tags { + s = append(s, tag.String()) + } + return "`" + strings.Join(s, " ") + "`" +} + +func (tags StructTags) Has(name string) bool { + for i := range tags { + if tags[i].Name == name { + return true + } + } + return false +} + +// ParseStructTags returns the full set of fields in a struct tag in the order they appear in +// the struct tag. +func ParseStructTags(tag string) (StructTags, error) { + tags := StructTags{} + for tag != "" { + // Skip leading space. + i := 0 + for i < len(tag) && tag[i] == ' ' { + i++ + } + tag = tag[i:] + if tag == "" { + break + } + + // Scan to colon. A space, a quote or a control character is a syntax error. + // Strictly speaking, control chars include the range [0x7f, 0x9f], not just + // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters + // as it is simpler to inspect the tag's bytes than the tag's runes. + i = 0 + for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f { + i++ + } + if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' { + break + } + name := string(tag[:i]) + tag = tag[i+1:] + + // Scan quoted string to find value. + i = 1 + for i < len(tag) && tag[i] != '"' { + if tag[i] == '\\' { + i++ + } + i++ + } + if i >= len(tag) { + break + } + qvalue := string(tag[:i+1]) + tag = tag[i+1:] + + value, err := strconv.Unquote(qvalue) + if err != nil { + return nil, err + } + tags = append(tags, StructTag{Name: name, Value: value}) + } + return tags, nil +} diff --git a/code-generator/tools.go b/code-generator/tools.go new file mode 100644 index 000000000..4080b2c59 --- /dev/null +++ b/code-generator/tools.go @@ -0,0 +1,35 @@ +//go:build tools +// +build tools + +/* +Copyright 2019 The Kubernetes 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. +*/ + +// This package contains code generation utilities +// This package imports things required by build scripts, to force `go mod` to see them as dependencies +package codegenerator + +import ( + _ "k8s.io/code-generator/cmd/applyconfiguration-gen" + _ "k8s.io/code-generator/cmd/client-gen" + _ "k8s.io/code-generator/cmd/conversion-gen" + _ "k8s.io/code-generator/cmd/deepcopy-gen" + _ "k8s.io/code-generator/cmd/defaulter-gen" + _ "k8s.io/code-generator/cmd/go-to-protobuf" + _ "k8s.io/code-generator/cmd/informer-gen" + _ "k8s.io/code-generator/cmd/lister-gen" + _ "k8s.io/code-generator/cmd/register-gen" + _ "k8s.io/kube-openapi/cmd/openapi-gen" +) diff --git a/code-generator/update-codegen.sh b/code-generator/update-codegen.sh new file mode 100755 index 000000000..726a11dff --- /dev/null +++ b/code-generator/update-codegen.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +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)} + +echo SCRIPT_ROOT=$SCRIPT_ROOT +echo CODEGEN_PKG=$CODEGEN_PKG + +source "${CODEGEN_PKG}/kube_codegen.sh" + +THIS_PKG="k8s.io/sample-controller" + +echo pwd=$(pwd) +kube::codegen::gen_helpers \ + --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \ + "${SCRIPT_ROOT}/pkg/apis" + +kube::codegen::gen_client \ + --with-watch \ + --output-dir "${SCRIPT_ROOT}/pkg/generated" \ + --output-pkg "${THIS_PKG}/pkg/generated" \ + --boilerplate "${SCRIPT_ROOT}/hack/boilerplate.go.txt" \ + "${SCRIPT_ROOT}/pkg/apis" diff --git a/controller.go b/controller.go index 75261b74d..1a612081a 100644 --- a/controller.go +++ b/controller.go @@ -39,11 +39,11 @@ import ( "k8s.io/client-go/util/workqueue" "k8s.io/klog/v2" - samplev1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1" - clientset "k8s.io/sample-controller/pkg/generated/clientset/versioned" - samplescheme "k8s.io/sample-controller/pkg/generated/clientset/versioned/scheme" - informers "k8s.io/sample-controller/pkg/generated/informers/externalversions/samplecontroller/v1alpha1" - listers "k8s.io/sample-controller/pkg/generated/listers/samplecontroller/v1alpha1" + samplev1alpha1 "github.com/woodliu/sample-controller/pkg/apis/samplecontroller/v1alpha1" + clientset "github.com/woodliu/sample-controller/pkg/generated/clientset/versioned" + samplescheme "github.com/woodliu/sample-controller/pkg/generated/clientset/versioned/scheme" + informers "github.com/woodliu/sample-controller/pkg/generated/informers/externalversions/samplecontroller/v1alpha1" + listers "github.com/woodliu/sample-controller/pkg/generated/listers/samplecontroller/v1alpha1" ) const controllerAgentName = "sample-controller" diff --git a/go.mod b/go.mod index 6d058f190..aee84a716 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ // This is a generated file. Do not edit directly. -module k8s.io/sample-controller +module github.com/woodliu/sample-controller go 1.23.0 diff --git a/main.go b/main.go index cda6ca198..471d47012 100644 --- a/main.go +++ b/main.go @@ -20,16 +20,16 @@ import ( "flag" "time" + "github.com/woodliu/sample-controller/pkg/signals" kubeinformers "k8s.io/client-go/informers" "k8s.io/client-go/kubernetes" "k8s.io/client-go/tools/clientcmd" "k8s.io/klog/v2" - "k8s.io/sample-controller/pkg/signals" // Uncomment the following line to load the gcp plugin (only required to authenticate against GKE clusters). // _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" - clientset "k8s.io/sample-controller/pkg/generated/clientset/versioned" - informers "k8s.io/sample-controller/pkg/generated/informers/externalversions" + clientset "github.com/woodliu/sample-controller/pkg/generated/clientset/versioned" + informers "github.com/woodliu/sample-controller/pkg/generated/informers/externalversions" ) var ( diff --git a/pkg/apis/samplecontroller/core/doc.go b/pkg/apis/samplecontroller/core/doc.go new file mode 100644 index 000000000..cfd68fd30 --- /dev/null +++ b/pkg/apis/samplecontroller/core/doc.go @@ -0,0 +1,2 @@ +// +k8s:deepcopy-gen=package +package core diff --git a/pkg/apis/samplecontroller/core/register.go b/pkg/apis/samplecontroller/core/register.go new file mode 100644 index 000000000..09e69c7f3 --- /dev/null +++ b/pkg/apis/samplecontroller/core/register.go @@ -0,0 +1,59 @@ +/* +Copyright 2014 The Kubernetes 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 core + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name use in this package +const GroupName = "" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} + +// Kind takes an unqualified kind and returns a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + // SchemeBuilder object to register various known types + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + + // AddToScheme represents a func that can be used to apply all the registered + // funcs in a scheme + AddToScheme = SchemeBuilder.AddToScheme +) + +func addKnownTypes(scheme *runtime.Scheme) error { + if err := scheme.AddIgnoredConversionType(&metav1.TypeMeta{}, &metav1.TypeMeta{}); err != nil { + return err + } + scheme.AddKnownTypes(SchemeGroupVersion, + &Foo{}, + ) + + return nil +} diff --git a/pkg/apis/samplecontroller/core/types.go b/pkg/apis/samplecontroller/core/types.go new file mode 100644 index 000000000..db3fd483a --- /dev/null +++ b/pkg/apis/samplecontroller/core/types.go @@ -0,0 +1,55 @@ +/* +Copyright 2017 The Kubernetes 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 core + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Foo is a specification for a Foo resource +type Foo struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec FooSpec `json:"spec"` + Status FooStatus `json:"status"` +} + +// FooSpec is the spec for a Foo resource +type FooSpec struct { + DeploymentName string `json:"deploymentName"` + Replicas *int32 `json:"replicas"` + Flag int32 `json:"flag"` +} + +// FooStatus is the status for a Foo resource +type FooStatus struct { + AvailableReplicas int32 `json:"availableReplicas"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// FooList is a list of Foo resources +type FooList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + + Items []Foo `json:"items"` +} diff --git a/pkg/apis/samplecontroller/v1alpha1/doc.go b/pkg/apis/samplecontroller/v1alpha1/doc.go index 398a0d346..fa7ad9bf1 100644 --- a/pkg/apis/samplecontroller/v1alpha1/doc.go +++ b/pkg/apis/samplecontroller/v1alpha1/doc.go @@ -15,6 +15,8 @@ limitations under the License. */ // +k8s:deepcopy-gen=package +// +k8s:defaulter-gen=TypeMeta +// +k8s:conversion-gen=github/woodliu/sample-controller/pkg/apis/samplecontroller/v1alpha1 // +groupName=samplecontroller.k8s.io // Package v1alpha1 is the v1alpha1 version of the API. diff --git a/pkg/apis/samplecontroller/v1alpha1/register.go b/pkg/apis/samplecontroller/v1alpha1/register.go index e8e0a28ef..7bfa03684 100644 --- a/pkg/apis/samplecontroller/v1alpha1/register.go +++ b/pkg/apis/samplecontroller/v1alpha1/register.go @@ -21,7 +21,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" - samplecontroller "k8s.io/sample-controller/pkg/apis/samplecontroller" + samplecontroller "github.com/woodliu/sample-controller/pkg/apis/samplecontroller" ) // SchemeGroupVersion is group version used to register these objects diff --git a/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/fake/fake_foo.go b/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/fake/fake_foo.go deleted file mode 100644 index f61c4e28f..000000000 --- a/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/fake/fake_foo.go +++ /dev/null @@ -1,147 +0,0 @@ -/* -Copyright The Kubernetes 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package fake - -import ( - context "context" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - labels "k8s.io/apimachinery/pkg/labels" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - testing "k8s.io/client-go/testing" - v1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1" -) - -// FakeFoos implements FooInterface -type FakeFoos struct { - Fake *FakeSamplecontrollerV1alpha1 - ns string -} - -var foosResource = v1alpha1.SchemeGroupVersion.WithResource("foos") - -var foosKind = v1alpha1.SchemeGroupVersion.WithKind("Foo") - -// Get takes name of the foo, and returns the corresponding foo object, and an error if there is any. -func (c *FakeFoos) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.Foo, err error) { - emptyResult := &v1alpha1.Foo{} - obj, err := c.Fake. - Invokes(testing.NewGetActionWithOptions(foosResource, c.ns, name, options), emptyResult) - - if obj == nil { - return emptyResult, err - } - return obj.(*v1alpha1.Foo), err -} - -// List takes label and field selectors, and returns the list of Foos that match those selectors. -func (c *FakeFoos) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.FooList, err error) { - emptyResult := &v1alpha1.FooList{} - obj, err := c.Fake. - Invokes(testing.NewListActionWithOptions(foosResource, foosKind, c.ns, opts), emptyResult) - - if obj == nil { - return emptyResult, err - } - - label, _, _ := testing.ExtractFromListOptions(opts) - if label == nil { - label = labels.Everything() - } - list := &v1alpha1.FooList{ListMeta: obj.(*v1alpha1.FooList).ListMeta} - for _, item := range obj.(*v1alpha1.FooList).Items { - if label.Matches(labels.Set(item.Labels)) { - list.Items = append(list.Items, item) - } - } - return list, err -} - -// Watch returns a watch.Interface that watches the requested foos. -func (c *FakeFoos) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { - return c.Fake. - InvokesWatch(testing.NewWatchActionWithOptions(foosResource, c.ns, opts)) - -} - -// Create takes the representation of a foo and creates it. Returns the server's representation of the foo, and an error, if there is any. -func (c *FakeFoos) Create(ctx context.Context, foo *v1alpha1.Foo, opts v1.CreateOptions) (result *v1alpha1.Foo, err error) { - emptyResult := &v1alpha1.Foo{} - obj, err := c.Fake. - Invokes(testing.NewCreateActionWithOptions(foosResource, c.ns, foo, opts), emptyResult) - - if obj == nil { - return emptyResult, err - } - return obj.(*v1alpha1.Foo), err -} - -// Update takes the representation of a foo and updates it. Returns the server's representation of the foo, and an error, if there is any. -func (c *FakeFoos) Update(ctx context.Context, foo *v1alpha1.Foo, opts v1.UpdateOptions) (result *v1alpha1.Foo, err error) { - emptyResult := &v1alpha1.Foo{} - obj, err := c.Fake. - Invokes(testing.NewUpdateActionWithOptions(foosResource, c.ns, foo, opts), emptyResult) - - if obj == nil { - return emptyResult, err - } - return obj.(*v1alpha1.Foo), err -} - -// UpdateStatus was generated because the type contains a Status member. -// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). -func (c *FakeFoos) UpdateStatus(ctx context.Context, foo *v1alpha1.Foo, opts v1.UpdateOptions) (result *v1alpha1.Foo, err error) { - emptyResult := &v1alpha1.Foo{} - obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceActionWithOptions(foosResource, "status", c.ns, foo, opts), emptyResult) - - if obj == nil { - return emptyResult, err - } - return obj.(*v1alpha1.Foo), err -} - -// Delete takes name of the foo and deletes it. Returns an error if one occurs. -func (c *FakeFoos) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { - _, err := c.Fake. - Invokes(testing.NewDeleteActionWithOptions(foosResource, c.ns, name, opts), &v1alpha1.Foo{}) - - return err -} - -// DeleteCollection deletes a collection of objects. -func (c *FakeFoos) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionActionWithOptions(foosResource, c.ns, opts, listOpts) - - _, err := c.Fake.Invokes(action, &v1alpha1.FooList{}) - return err -} - -// Patch applies the patch and returns the patched foo. -func (c *FakeFoos) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.Foo, err error) { - emptyResult := &v1alpha1.Foo{} - obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceActionWithOptions(foosResource, c.ns, name, pt, data, opts, subresources...), emptyResult) - - if obj == nil { - return emptyResult, err - } - return obj.(*v1alpha1.Foo), err -} diff --git a/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/foo.go b/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/foo.go deleted file mode 100644 index 47e32500b..000000000 --- a/pkg/generated/clientset/versioned/typed/samplecontroller/v1alpha1/foo.go +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright The Kubernetes 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. -*/ - -// Code generated by client-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - context "context" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - types "k8s.io/apimachinery/pkg/types" - watch "k8s.io/apimachinery/pkg/watch" - gentype "k8s.io/client-go/gentype" - samplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1" - scheme "k8s.io/sample-controller/pkg/generated/clientset/versioned/scheme" -) - -// FoosGetter has a method to return a FooInterface. -// A group's client should implement this interface. -type FoosGetter interface { - Foos(namespace string) FooInterface -} - -// FooInterface has methods to work with Foo resources. -type FooInterface interface { - Create(ctx context.Context, foo *samplecontrollerv1alpha1.Foo, opts v1.CreateOptions) (*samplecontrollerv1alpha1.Foo, error) - Update(ctx context.Context, foo *samplecontrollerv1alpha1.Foo, opts v1.UpdateOptions) (*samplecontrollerv1alpha1.Foo, error) - // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). - UpdateStatus(ctx context.Context, foo *samplecontrollerv1alpha1.Foo, opts v1.UpdateOptions) (*samplecontrollerv1alpha1.Foo, error) - Delete(ctx context.Context, name string, opts v1.DeleteOptions) error - DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error - Get(ctx context.Context, name string, opts v1.GetOptions) (*samplecontrollerv1alpha1.Foo, error) - List(ctx context.Context, opts v1.ListOptions) (*samplecontrollerv1alpha1.FooList, error) - Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) - Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *samplecontrollerv1alpha1.Foo, err error) - FooExpansion -} - -// foos implements FooInterface -type foos struct { - *gentype.ClientWithList[*samplecontrollerv1alpha1.Foo, *samplecontrollerv1alpha1.FooList] -} - -// newFoos returns a Foos -func newFoos(c *SamplecontrollerV1alpha1Client, namespace string) *foos { - return &foos{ - gentype.NewClientWithList[*samplecontrollerv1alpha1.Foo, *samplecontrollerv1alpha1.FooList]( - "foos", - c.RESTClient(), - scheme.ParameterCodec, - namespace, - func() *samplecontrollerv1alpha1.Foo { return &samplecontrollerv1alpha1.Foo{} }, - func() *samplecontrollerv1alpha1.FooList { return &samplecontrollerv1alpha1.FooList{} }), - } -} diff --git a/pkg/generated/informers/externalversions/samplecontroller/v1alpha1/foo.go b/pkg/generated/informers/externalversions/samplecontroller/v1alpha1/foo.go deleted file mode 100644 index 3d3ce74bb..000000000 --- a/pkg/generated/informers/externalversions/samplecontroller/v1alpha1/foo.go +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright The Kubernetes 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. -*/ - -// Code generated by informer-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - context "context" - time "time" - - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" - watch "k8s.io/apimachinery/pkg/watch" - cache "k8s.io/client-go/tools/cache" - apissamplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1" - versioned "k8s.io/sample-controller/pkg/generated/clientset/versioned" - internalinterfaces "k8s.io/sample-controller/pkg/generated/informers/externalversions/internalinterfaces" - samplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/generated/listers/samplecontroller/v1alpha1" -) - -// FooInformer provides access to a shared informer and lister for -// Foos. -type FooInformer interface { - Informer() cache.SharedIndexInformer - Lister() samplecontrollerv1alpha1.FooLister -} - -type fooInformer struct { - factory internalinterfaces.SharedInformerFactory - tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string -} - -// NewFooInformer constructs a new informer for Foo type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFooInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredFooInformer(client, namespace, resyncPeriod, indexers, nil) -} - -// NewFilteredFooInformer constructs a new informer for Foo type. -// Always prefer using an informer factory to get a shared informer instead of getting an independent -// one. This reduces memory footprint and number of connections to the server. -func NewFilteredFooInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { - return cache.NewSharedIndexInformer( - &cache.ListWatch{ - ListFunc: func(options v1.ListOptions) (runtime.Object, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.SamplecontrollerV1alpha1().Foos(namespace).List(context.TODO(), options) - }, - WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { - if tweakListOptions != nil { - tweakListOptions(&options) - } - return client.SamplecontrollerV1alpha1().Foos(namespace).Watch(context.TODO(), options) - }, - }, - &apissamplecontrollerv1alpha1.Foo{}, - resyncPeriod, - indexers, - ) -} - -func (f *fooInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredFooInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) -} - -func (f *fooInformer) Informer() cache.SharedIndexInformer { - return f.factory.InformerFor(&apissamplecontrollerv1alpha1.Foo{}, f.defaultInformer) -} - -func (f *fooInformer) Lister() samplecontrollerv1alpha1.FooLister { - return samplecontrollerv1alpha1.NewFooLister(f.Informer().GetIndexer()) -} diff --git a/pkg/generated/listers/samplecontroller/v1alpha1/foo.go b/pkg/generated/listers/samplecontroller/v1alpha1/foo.go deleted file mode 100644 index cbe948fe3..000000000 --- a/pkg/generated/listers/samplecontroller/v1alpha1/foo.go +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright The Kubernetes 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. -*/ - -// Code generated by lister-gen. DO NOT EDIT. - -package v1alpha1 - -import ( - labels "k8s.io/apimachinery/pkg/labels" - listers "k8s.io/client-go/listers" - cache "k8s.io/client-go/tools/cache" - samplecontrollerv1alpha1 "k8s.io/sample-controller/pkg/apis/samplecontroller/v1alpha1" -) - -// FooLister helps list Foos. -// All objects returned here must be treated as read-only. -type FooLister interface { - // List lists all Foos in the indexer. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*samplecontrollerv1alpha1.Foo, err error) - // Foos returns an object that can list and get Foos. - Foos(namespace string) FooNamespaceLister - FooListerExpansion -} - -// fooLister implements the FooLister interface. -type fooLister struct { - listers.ResourceIndexer[*samplecontrollerv1alpha1.Foo] -} - -// NewFooLister returns a new FooLister. -func NewFooLister(indexer cache.Indexer) FooLister { - return &fooLister{listers.New[*samplecontrollerv1alpha1.Foo](indexer, samplecontrollerv1alpha1.Resource("foo"))} -} - -// Foos returns an object that can list and get Foos. -func (s *fooLister) Foos(namespace string) FooNamespaceLister { - return fooNamespaceLister{listers.NewNamespaced[*samplecontrollerv1alpha1.Foo](s.ResourceIndexer, namespace)} -} - -// FooNamespaceLister helps list and get Foos. -// All objects returned here must be treated as read-only. -type FooNamespaceLister interface { - // List lists all Foos in the indexer for a given namespace. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*samplecontrollerv1alpha1.Foo, err error) - // Get retrieves the Foo from the indexer for a given namespace and name. - // Objects returned here must be treated as read-only. - Get(name string) (*samplecontrollerv1alpha1.Foo, error) - FooNamespaceListerExpansion -} - -// fooNamespaceLister implements the FooNamespaceLister -// interface. -type fooNamespaceLister struct { - listers.ResourceIndexer[*samplecontrollerv1alpha1.Foo] -}