diff --git a/build/root/Makefile.generated_files b/build/root/Makefile.generated_files index c8cbf27997f..56baab15802 100644 --- a/build/root/Makefile.generated_files +++ b/build/root/Makefile.generated_files @@ -35,7 +35,7 @@ SHELL := /bin/bash # This rule collects all the generated file sets into a single rule. Other # rules should depend on this to ensure generated files are rebuilt. .PHONY: generated_files -generated_files: gen_deepcopy gen_defaulter gen_conversion gen_openapi gen_bindata +generated_files: gen_prerelease_lifecycle gen_deepcopy gen_defaulter gen_conversion gen_openapi gen_bindata # # Helper logic to calculate Go's dependency DAG ourselves. @@ -112,6 +112,90 @@ ALL_K8S_TAG_FILES := $(shell \ # +# prerelease-lifecycle generation +# +# Any package that wants prerelease-lifecycle functions generated must include a +# comment-tag in column 0 of one file of the form: +# // +k8s:prerelease-lifecycle-gen=true +# + +# The result file, in each pkg, of deep-copy generation. +PRERELEASE_LIFECYCLE_BASENAME := $(GENERATED_FILE_PREFIX)prerelease-lifecycle +PRERELEASE_LIFECYCLE_FILENAME := $(PRERELEASE_LIFECYCLE_BASENAME).go + +# The tool used to generate deep copies. +PRERELEASE_LIFECYCLE_GEN := $(BIN_DIR)/prerelease-lifecycle-gen + +# Find all the directories that request deep-copy generation. +ifeq ($(DBG_MAKEFILE),1) + $(warning ***** finding all +k8s:prerelease-lifecycle-gen tags) +endif +PRERELEASE_LIFECYCLE_DIRS := $(shell \ + grep --color=never -l '+k8s:prerelease-lifecycle-gen=' $(ALL_K8S_TAG_FILES) \ + | xargs -n1 dirname \ + | LC_ALL=C sort -u \ +) +PRERELEASE_LIFECYCLE_FILES := $(addsuffix /$(PRERELEASE_LIFECYCLE_FILENAME), $(PRERELEASE_LIFECYCLE_DIRS)) + +# Reset the list of packages that need generation. +$(shell mkdir -p $$(dirname $(META_DIR)/$(PRERELEASE_LIFECYCLE_GEN))) +$(shell rm -f $(META_DIR)/$(PRERELEASE_LIFECYCLE_GEN).todo) + +# This rule aggregates the set of files to generate and then generates them all +# in a single run of the tool. +.PHONY: gen_prerelease_lifecycle +gen_prerelease_lifecycle: $(PRERELEASE_LIFECYCLE_GEN) $(META_DIR)/$(PRERELEASE_LIFECYCLE_GEN).todo + if [[ -s $(META_DIR)/$(PRERELEASE_LIFECYCLE_GEN).todo ]]; then \ + pkgs=$$(cat $(META_DIR)/$(PRERELEASE_LIFECYCLE_GEN).todo | paste -sd, -); \ + if [[ "$(DBG_CODEGEN)" == 1 ]]; then \ + echo "DBG: running $(PRERELEASE_LIFECYCLE_GEN) for $$pkgs"; \ + fi; \ + ./hack/run-in-gopath.sh $(PRERELEASE_LIFECYCLE_GEN) \ + --v $(KUBE_VERBOSE) \ + --logtostderr \ + -i "$$pkgs" \ + -O $(PRERELEASE_LIFECYCLE_BASENAME) \ + "$$@"; \ + fi \ + +# For each dir in PRERELEASE_LIFECYCLE_DIRS, this establishes a dependency between the +# output file and the input files that should trigger a rebuild. +# +# Note that this is a deps-only statement, not a full rule (see below). This +# has to be done in a distinct step because wildcards don't work in static +# pattern rules. +# +# The '$(eval)' is needed because this has a different RHS for each LHS, and +# would otherwise produce results that make can't parse. +$(foreach dir, $(PRERELEASE_LIFECYCLE_DIRS), $(eval \ + $(dir)/$(PRERELEASE_LIFECYCLE_FILENAME): $($(PRJ_SRC_PATH)/$(dir)) \ +)) + +# How to regenerate deep-copy code. This is a little slow to run, so we batch +# it up and trigger the batch from the 'generated_files' target. +$(META_DIR)/$(PRERELEASE_LIFECYCLE_GEN).todo: $(PRERELEASE_LIFECYCLE_FILES) + +$(PRERELEASE_LIFECYCLE_FILES): $(PRERELEASE_LIFECYCLE_GEN) + if [[ "$(DBG_CODEGEN)" == 1 ]]; then \ + echo "DBG: prerelease-lifecycle needed $(@D):"; \ + ls -lf --full-time $@ $? || true; \ + fi + echo $(PRJ_SRC_PATH)/$(@D) >> $(META_DIR)/$(PRERELEASE_LIFECYCLE_GEN).todo + +# How to build the generator tool. The deps for this are defined in +# the $(GO_PKGDEPS_FILE), above. +# +# A word on the need to touch: This rule might trigger if, for example, a +# non-Go file was added or deleted from a directory on which this depends. +# This target needs to be reconsidered, but Go realizes it doesn't actually +# have to be rebuilt. In that case, make will forever see the dependency as +# newer than the binary, and try to "rebuild" it over and over. So we touch +# it, and make is happy. +$(PRERELEASE_LIFECYCLE_GEN): $(k8s.io/kubernetes/vendor/k8s.io/code-generator/cmd/prerelease-lifecycle-gen) + KUBE_BUILD_PLATFORMS="" hack/make-rules/build.sh ./vendor/k8s.io/code-generator/cmd/prerelease-lifecycle-gen + touch $@ + + # Deep-copy generation # # Any package that wants deep-copy functions generated must include a diff --git a/staging/src/k8s.io/api/extensions/v1beta1/BUILD b/staging/src/k8s.io/api/extensions/v1beta1/BUILD index ce7106a2dfc..59e2564b2b0 100644 --- a/staging/src/k8s.io/api/extensions/v1beta1/BUILD +++ b/staging/src/k8s.io/api/extensions/v1beta1/BUILD @@ -14,6 +14,7 @@ go_library( "types.go", "types_swagger_doc_generated.go", "zz_generated.deepcopy.go", + "zz_generated.prerelease-lifecycle.go", ], importmap = "k8s.io/kubernetes/vendor/k8s.io/api/extensions/v1beta1", importpath = "k8s.io/api/extensions/v1beta1", diff --git a/staging/src/k8s.io/api/extensions/v1beta1/doc.go b/staging/src/k8s.io/api/extensions/v1beta1/doc.go index fa799f30261..c9af49d55c7 100644 --- a/staging/src/k8s.io/api/extensions/v1beta1/doc.go +++ b/staging/src/k8s.io/api/extensions/v1beta1/doc.go @@ -17,5 +17,6 @@ limitations under the License. // +k8s:deepcopy-gen=package // +k8s:protobuf-gen=package // +k8s:openapi-gen=true +// +k8s:prerelease-lifecycle-gen=true package v1beta1 // import "k8s.io/api/extensions/v1beta1" diff --git a/staging/src/k8s.io/api/extensions/v1beta1/types.go b/staging/src/k8s.io/api/extensions/v1beta1/types.go index 8934c06137a..a9401b78a95 100644 --- a/staging/src/k8s.io/api/extensions/v1beta1/types.go +++ b/staging/src/k8s.io/api/extensions/v1beta1/types.go @@ -50,6 +50,9 @@ type ScaleStatus struct { } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.1 +// +k8s:prerelease-lifecycle-gen:deprecated=1.2 +// +k8s:prerelease-lifecycle-gen:removed=1.18 // represents a scaling request for a resource. type Scale struct { @@ -71,6 +74,9 @@ type Scale struct { // +genclient:method=GetScale,verb=get,subresource=scale,result=Scale // +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.1 +// +k8s:prerelease-lifecycle-gen:deprecated=1.8 +// +k8s:prerelease-lifecycle-gen:removed=1.18 // DEPRECATED - This group version of Deployment is deprecated by apps/v1beta2/Deployment. See the release notes for // more information. @@ -144,6 +150,9 @@ type DeploymentSpec struct { } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.2 +// +k8s:prerelease-lifecycle-gen:deprecated=1.8 +// +k8s:prerelease-lifecycle-gen:removed=1.18 // DEPRECATED. // DeploymentRollback stores the information required to rollback a deployment. @@ -301,6 +310,9 @@ type DeploymentCondition struct { } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.1 +// +k8s:prerelease-lifecycle-gen:deprecated=1.8 +// +k8s:prerelease-lifecycle-gen:removed=1.18 // DeploymentList is a list of Deployments. type DeploymentList struct { @@ -475,6 +487,9 @@ type DaemonSetCondition struct { // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.1 +// +k8s:prerelease-lifecycle-gen:deprecated=1.8 +// +k8s:prerelease-lifecycle-gen:removed=1.18 // DEPRECATED - This group version of DaemonSet is deprecated by apps/v1beta2/DaemonSet. See the release notes for // more information. @@ -514,6 +529,9 @@ const ( ) // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.1 +// +k8s:prerelease-lifecycle-gen:deprecated=1.8 +// +k8s:prerelease-lifecycle-gen:removed=1.18 // DaemonSetList is a collection of daemon sets. type DaemonSetList struct { @@ -529,6 +547,9 @@ type DaemonSetList struct { // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.1 +// +k8s:prerelease-lifecycle-gen:deprecated=1.14 +// +k8s:prerelease-lifecycle-gen:removed=1.22 // Ingress is a collection of rules that allow inbound connections to reach the // endpoints defined by a backend. An Ingress can be configured to give services @@ -554,6 +575,9 @@ type Ingress struct { } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.1 +// +k8s:prerelease-lifecycle-gen:deprecated=1.14 +// +k8s:prerelease-lifecycle-gen:removed=1.22 // IngressList is a collection of Ingress. type IngressList struct { @@ -776,6 +800,9 @@ type IngressBackend struct { // +genclient:method=GetScale,verb=get,subresource=scale,result=Scale // +genclient:method=UpdateScale,verb=update,subresource=scale,input=Scale,result=Scale // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.2 +// +k8s:prerelease-lifecycle-gen:deprecated=1.8 +// +k8s:prerelease-lifecycle-gen:removed=1.18 // DEPRECATED - This group version of ReplicaSet is deprecated by apps/v1beta2/ReplicaSet. See the release notes for // more information. @@ -804,6 +831,9 @@ type ReplicaSet struct { } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.2 +// +k8s:prerelease-lifecycle-gen:deprecated=1.8 +// +k8s:prerelease-lifecycle-gen:removed=1.18 // ReplicaSetList is a collection of ReplicaSets. type ReplicaSetList struct { @@ -906,6 +936,9 @@ type ReplicaSetCondition struct { // +genclient // +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.2 +// +k8s:prerelease-lifecycle-gen:deprecated=1.11 +// +k8s:prerelease-lifecycle-gen:removed=1.18 // PodSecurityPolicy governs the ability to make requests that affect the Security Context // that will be applied to a pod and container. @@ -1264,6 +1297,9 @@ type RuntimeClassStrategyOptions struct { const AllowAllRuntimeClassNames = "*" // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.2 +// +k8s:prerelease-lifecycle-gen:deprecated=1.11 +// +k8s:prerelease-lifecycle-gen:removed=1.18 // PodSecurityPolicyList is a list of PodSecurityPolicy objects. // Deprecated: use PodSecurityPolicyList from policy API Group instead. @@ -1280,6 +1316,9 @@ type PodSecurityPolicyList struct { // +genclient // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.3 +// +k8s:prerelease-lifecycle-gen:deprecated=1.9 +// +k8s:prerelease-lifecycle-gen:removed=1.18 // DEPRECATED 1.9 - This group version of NetworkPolicy is deprecated by networking/v1/NetworkPolicy. // NetworkPolicy describes what network traffic is allowed for a set of Pods @@ -1450,6 +1489,9 @@ type NetworkPolicyPeer struct { } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object +// +k8s:prerelease-lifecycle-gen:introduced=1.3 +// +k8s:prerelease-lifecycle-gen:deprecated=1.9 +// +k8s:prerelease-lifecycle-gen:removed=1.18 // DEPRECATED 1.9 - This group version of NetworkPolicyList is deprecated by networking/v1/NetworkPolicyList. // Network Policy List is a list of NetworkPolicy objects. diff --git a/staging/src/k8s.io/api/extensions/v1beta1/zz_generated.prerelease-lifecycle.go b/staging/src/k8s.io/api/extensions/v1beta1/zz_generated.prerelease-lifecycle.go new file mode 100644 index 00000000000..fd54381e78c --- /dev/null +++ b/staging/src/k8s.io/api/extensions/v1beta1/zz_generated.prerelease-lifecycle.go @@ -0,0 +1,273 @@ +// +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 prerelease-lifecycle-gen. DO NOT EDIT. + +package v1beta1 + +// Introduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go. +func (in *DaemonSet) Introduced() (int64, int64) { + return 1, 1 +} + +// Deprecated 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. +// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor. +func (in *DaemonSet) Deprecated() (int64, int64) { + return 1, 8 +} + +// Removed is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor. +func (in *DaemonSet) Removed() (int64, int64) { + return 1, 18 +} + +// Introduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go. +func (in *DaemonSetList) Introduced() (int64, int64) { + return 1, 1 +} + +// Deprecated 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. +// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor. +func (in *DaemonSetList) Deprecated() (int64, int64) { + return 1, 8 +} + +// Removed is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor. +func (in *DaemonSetList) Removed() (int64, int64) { + return 1, 18 +} + +// Introduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go. +func (in *Deployment) Introduced() (int64, int64) { + return 1, 1 +} + +// Deprecated 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. +// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor. +func (in *Deployment) Deprecated() (int64, int64) { + return 1, 8 +} + +// Removed is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor. +func (in *Deployment) Removed() (int64, int64) { + return 1, 18 +} + +// Introduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go. +func (in *DeploymentList) Introduced() (int64, int64) { + return 1, 1 +} + +// Deprecated 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. +// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor. +func (in *DeploymentList) Deprecated() (int64, int64) { + return 1, 8 +} + +// Removed is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor. +func (in *DeploymentList) Removed() (int64, int64) { + return 1, 18 +} + +// Introduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go. +func (in *DeploymentRollback) Introduced() (int64, int64) { + return 1, 2 +} + +// Deprecated 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. +// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor. +func (in *DeploymentRollback) Deprecated() (int64, int64) { + return 1, 8 +} + +// Removed is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor. +func (in *DeploymentRollback) Removed() (int64, int64) { + return 1, 18 +} + +// Introduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go. +func (in *Ingress) Introduced() (int64, int64) { + return 1, 1 +} + +// Deprecated 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. +// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor. +func (in *Ingress) Deprecated() (int64, int64) { + return 1, 14 +} + +// Removed is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor. +func (in *Ingress) Removed() (int64, int64) { + return 1, 22 +} + +// Introduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go. +func (in *IngressList) Introduced() (int64, int64) { + return 1, 1 +} + +// Deprecated 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. +// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor. +func (in *IngressList) Deprecated() (int64, int64) { + return 1, 14 +} + +// Removed is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor. +func (in *IngressList) Removed() (int64, int64) { + return 1, 22 +} + +// Introduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go. +func (in *NetworkPolicy) Introduced() (int64, int64) { + return 1, 3 +} + +// Deprecated 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. +// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor. +func (in *NetworkPolicy) Deprecated() (int64, int64) { + return 1, 9 +} + +// Removed is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor. +func (in *NetworkPolicy) Removed() (int64, int64) { + return 1, 18 +} + +// Introduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go. +func (in *NetworkPolicyList) Introduced() (int64, int64) { + return 1, 3 +} + +// Deprecated 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. +// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor. +func (in *NetworkPolicyList) Deprecated() (int64, int64) { + return 1, 9 +} + +// Removed is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor. +func (in *NetworkPolicyList) Removed() (int64, int64) { + return 1, 18 +} + +// Introduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go. +func (in *PodSecurityPolicy) Introduced() (int64, int64) { + return 1, 2 +} + +// Deprecated 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. +// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor. +func (in *PodSecurityPolicy) Deprecated() (int64, int64) { + return 1, 11 +} + +// Removed is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor. +func (in *PodSecurityPolicy) Removed() (int64, int64) { + return 1, 18 +} + +// Introduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go. +func (in *PodSecurityPolicyList) Introduced() (int64, int64) { + return 1, 2 +} + +// Deprecated 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. +// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor. +func (in *PodSecurityPolicyList) Deprecated() (int64, int64) { + return 1, 11 +} + +// Removed is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor. +func (in *PodSecurityPolicyList) Removed() (int64, int64) { + return 1, 18 +} + +// Introduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go. +func (in *ReplicaSet) Introduced() (int64, int64) { + return 1, 2 +} + +// Deprecated 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. +// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor. +func (in *ReplicaSet) Deprecated() (int64, int64) { + return 1, 8 +} + +// Removed is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor. +func (in *ReplicaSet) Removed() (int64, int64) { + return 1, 18 +} + +// Introduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go. +func (in *ReplicaSetList) Introduced() (int64, int64) { + return 1, 2 +} + +// Deprecated 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. +// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor. +func (in *ReplicaSetList) Deprecated() (int64, int64) { + return 1, 8 +} + +// Removed is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor. +func (in *ReplicaSetList) Removed() (int64, int64) { + return 1, 18 +} + +// Introduced is an autogenerated function, returning the release in which the API struct was introduced as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:introduced" tags in types.go. +func (in *Scale) Introduced() (int64, int64) { + return 1, 1 +} + +// Deprecated 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. +// It is controlled by "k8s:prerelease-lifecycle-gen:deprecated" tags in types.go or "k8s:prerelease-lifecycle-gen:introduced" plus three minor. +func (in *Scale) Deprecated() (int64, int64) { + return 1, 2 +} + +// Removed is an autogenerated function, returning the release in which the API is no longer served as int versions of major and minor for comparison. +// It is controlled by "k8s:prerelease-lifecycle-gen:removed" tags in types.go or "k8s:prerelease-lifecycle-gen:deprecated" plus three minor. +func (in *Scale) Removed() (int64, int64) { + return 1, 18 +} diff --git a/staging/src/k8s.io/code-generator/BUILD b/staging/src/k8s.io/code-generator/BUILD index dba504fa569..9a0f1f65304 100644 --- a/staging/src/k8s.io/code-generator/BUILD +++ b/staging/src/k8s.io/code-generator/BUILD @@ -18,6 +18,7 @@ filegroup( "//staging/src/k8s.io/code-generator/cmd/informer-gen:all-srcs", "//staging/src/k8s.io/code-generator/cmd/lister-gen:all-srcs", "//staging/src/k8s.io/code-generator/cmd/openapi-gen:all-srcs", + "//staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen:all-srcs", "//staging/src/k8s.io/code-generator/cmd/register-gen:all-srcs", "//staging/src/k8s.io/code-generator/cmd/set-gen:all-srcs", "//staging/src/k8s.io/code-generator/hack:all-srcs", diff --git a/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/BUILD b/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/BUILD new file mode 100644 index 00000000000..6e26013bb56 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/BUILD @@ -0,0 +1,41 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") + +go_library( + name = "go_default_library", + srcs = ["main.go"], + importmap = "k8s.io/kubernetes/vendor/k8s.io/code-generator/cmd/prerelease-lifecycle-gen", + importpath = "k8s.io/code-generator/cmd/prerelease-lifecycle-gen", + visibility = ["//visibility:private"], + deps = [ + "//staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args:go_default_library", + "//staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators:go_default_library", + "//staging/src/k8s.io/code-generator/pkg/util:go_default_library", + "//vendor/github.com/spf13/pflag:go_default_library", + "//vendor/k8s.io/gengo/args:go_default_library", + "//vendor/k8s.io/klog:go_default_library", + ], +) + +go_binary( + name = "status-gen", + embed = [":go_default_library"], + visibility = ["//visibility:public"], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [ + ":package-srcs", + "//staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args:all-srcs", + "//staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators:all-srcs", + ], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args/BUILD b/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args/BUILD new file mode 100644 index 00000000000..6f0670e9b37 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args/BUILD @@ -0,0 +1,28 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["args.go"], + importmap = "k8s.io/kubernetes/vendor/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args", + importpath = "k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args", + visibility = ["//visibility:public"], + deps = [ + "//staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators:go_default_library", + "//vendor/github.com/spf13/pflag:go_default_library", + "//vendor/k8s.io/gengo/args:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args/args.go b/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args/args.go new file mode 100644 index 00000000000..ca23a90fc71 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args/args.go @@ -0,0 +1,52 @@ +/* +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" + statusgenerators "k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators" + "k8s.io/gengo/args" +) + +// CustomArgs is used by the gengo framework to pass args specific to this generator. +type CustomArgs statusgenerators.CustomArgs + +// NewDefaults returns default arguments for the generator. +func NewDefaults() (*args.GeneratorArgs, *CustomArgs) { + genericArgs := args.Default().WithoutDefaultFlagParsing() + customArgs := &CustomArgs{} + genericArgs.CustomArgs = (*statusgenerators.CustomArgs)(customArgs) // convert to upstream type to make type-casts work there + genericArgs.OutputFileBaseName = "zz_prerelease_lifecycle_generated" + return genericArgs, customArgs +} + +// AddFlags add the generator flags to the flag set. +func (ca *CustomArgs) AddFlags(fs *pflag.FlagSet) { +} + +// Validate checks the given arguments. +func Validate(genericArgs *args.GeneratorArgs) error { + _ = genericArgs.CustomArgs.(*statusgenerators.CustomArgs) + + if len(genericArgs.OutputFileBaseName) == 0 { + return fmt.Errorf("output file base name cannot be empty") + } + + return nil +} diff --git a/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/main.go b/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/main.go new file mode 100644 index 00000000000..441e48592f1 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/main.go @@ -0,0 +1,74 @@ +/* +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=package +// +// // +k8s:prerelease-lifecycle-gen:introduced=1.19 +// // +k8s:prerelease-lifecycle-gen:to-be-deprecated=1.22 +// // +k8s:prerelease-lifecycle-gen:to-be-removed=1.25 +// +// Note that registration is a whole-package option, and is not available for +// individual types. +package main + +import ( + "flag" + "path/filepath" + + "github.com/spf13/pflag" + generatorargs "k8s.io/code-generator/cmd/prerelease-lifecycle-gen/args" + statusgenerators "k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators" + "k8s.io/code-generator/pkg/util" + "k8s.io/gengo/args" + "k8s.io/klog" +) + +func main() { + klog.InitFlags(nil) + genericArgs, customArgs := generatorargs.NewDefaults() + + // Override defaults. + // TODO: move this out of prerelease-lifecycle-gen + genericArgs.GoHeaderFilePath = filepath.Join(args.DefaultSourceTree(), util.BoilerplatePath()) + + genericArgs.AddFlags(pflag.CommandLine) + customArgs.AddFlags(pflag.CommandLine) + flag.Set("logtostderr", "true") + pflag.CommandLine.AddGoFlagSet(flag.CommandLine) + pflag.Parse() + + if err := generatorargs.Validate(genericArgs); err != nil { + klog.Fatalf("Error: %v", err) + } + + // Run it. + if err := genericArgs.Execute( + statusgenerators.NameSystems(), + statusgenerators.DefaultNameSystem(), + statusgenerators.Packages, + ); err != nil { + klog.Fatalf("Error: %v", err) + } + klog.V(2).Info("Completed successfully.") +} diff --git a/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators/BUILD b/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators/BUILD new file mode 100644 index 00000000000..1c4565ddb13 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators/BUILD @@ -0,0 +1,31 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +go_library( + name = "go_default_library", + srcs = ["status.go"], + importmap = "k8s.io/kubernetes/vendor/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators", + importpath = "k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators", + visibility = ["//visibility:public"], + deps = [ + "//vendor/k8s.io/gengo/args:go_default_library", + "//vendor/k8s.io/gengo/examples/set-gen/sets:go_default_library", + "//vendor/k8s.io/gengo/generator:go_default_library", + "//vendor/k8s.io/gengo/namer:go_default_library", + "//vendor/k8s.io/gengo/types:go_default_library", + "//vendor/k8s.io/klog:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], + visibility = ["//visibility:public"], +) diff --git a/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators/status.go b/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators/status.go new file mode 100644 index 00000000000..a72bda1de04 --- /dev/null +++ b/staging/src/k8s.io/code-generator/cmd/prerelease-lifecycle-gen/prerelease-lifecycle-generators/status.go @@ -0,0 +1,438 @@ +/* +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/filepath" + "strconv" + "strings" + + "k8s.io/gengo/args" + "k8s.io/gengo/examples/set-gen/sets" + "k8s.io/gengo/generator" + "k8s.io/gengo/namer" + "k8s.io/gengo/types" + + "k8s.io/klog" +) + +// CustomArgs is used tby the go2idl framework to pass args specific to this generator. +type CustomArgs struct { +} + +// 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" +) + +// 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, int64, int64, 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[0]) == 0 { + return nil, -1, -1, fmt.Errorf("%v format must match %v=xx.yy tag", t, tagName) + } + major, err := strconv.ParseInt(splitValue[0], 10, 64) + 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, 64) + if err != nil { + return nil, -1, -1, fmt.Errorf("%v format must match %v=xx.yy : %w", t, tagName, err) + } + + return rawTag, major, minor, nil +} + +func extractIntroducedTag(t *types.Type) (*tagValue, int64, int64, error) { + return extractKubeVersionTag(introducedTagName, t) +} + +func extractDeprecatedTag(t *types.Type) (*tagValue, int64, int64, error) { + return extractKubeVersionTag(deprecatedTagName, t) +} + +func extractRemovedTag(t *types.Type) (*tagValue, int64, int64, error) { + return extractKubeVersionTag(removedTagName, t) +} + +func extractTag(tagName string, comments []string) *tagValue { + tagVals := types.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] + //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", 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" +} + +// Packages makes the package definition. +func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages { + boilerplate, err := arguments.LoadGoBoilerplate() + if err != nil { + klog.Fatalf("Failed loading boilerplate: %v", err) + } + + inputs := sets.NewString(context.Inputs...) + packages := generator.Packages{} + header := append([]byte(fmt.Sprintf("// +build !%s\n\n", arguments.GeneratedBuildTag)), boilerplate...) + + for i := range inputs { + klog.V(5).Infof("Considering pkg %q", i) + pkg := context.Universe[i] + if pkg == nil { + // If the input had no Go files, for example. + continue + } + + 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 :%w", i, tagEnabledName, ptag.value, err) + } + } + if !pkgNeedsGeneration { + klog.V(5).Infof(" skipping package") + continue + } + klog.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 deepcopy generation but is not copyable", t) + } + pkgNeedsGeneration = true + break + } + } + } + + if pkgNeedsGeneration { + path := pkg.Path + // if the source path is within a /vendor/ directory (for example, + // k8s.io/kubernetes/vendor/k8s.io/apimachinery/pkg/apis/meta/v1), allow + // generation to output to the proper relative path (under vendor). + // Otherwise, the generator will create the file in the wrong location + // in the output directory. + // TODO: build a more fundamental concept in gengo for dealing with modifications + // to vendored packages. + if strings.HasPrefix(pkg.SourcePath, arguments.OutputBase) { + expandedPath := strings.TrimPrefix(pkg.SourcePath, arguments.OutputBase) + if strings.Contains(expandedPath, "/vendor/") { + path = expandedPath + } + } + packages = append(packages, + &generator.DefaultPackage{ + PackageName: strings.Split(filepath.Base(pkg.Path), ".")[0], + PackagePath: path, + HeaderText: header, + GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { + return []generator.Generator{ + NewPrereleaseLifecycleGen(arguments.OutputFileBaseName, pkg.Path), + } + }, + FilterFunc: func(c *generator.Context, t *types.Type) bool { + return t.Name.Package == pkg.Path + }, + }) + } + } + return packages +} + +// genDeepCopy produces a file with autogenerated deep-copy functions. +type genPreleaseLifecycle struct { + generator.DefaultGen + targetPackage string + imports namer.ImportTracker + typesForInit []*types.Type +} + +// NewPrereleaseLifecycleGen creates a generator for the prerelease-lifecycle-generator +func NewPrereleaseLifecycleGen(sanitizedName, targetPackage string) generator.Generator { + return &genPreleaseLifecycle{ + DefaultGen: generator.DefaultGen{ + OptionalName: sanitizedName, + }, + 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 +} + +func argsFromType(t *types.Type) (generator.Args, error) { + a := generator.Args{ + "type": t, + } + _, introducedMajor, introducedMinor, err := extractIntroducedTag(t) + if err != nil { + return nil, err + } + a = a. + With("introducedMajor", introducedMajor). + With("introducedMinor", introducedMinor) + + // compute based on our policy + deprecatedMajor := introducedMajor + deprecatedMinor := introducedMinor + 3 + // if someone intentionally override the deprecation release + if tagExists(deprecatedTagName, t) { + _, deprecatedMajor, deprecatedMinor, err = extractDeprecatedTag(t) + if err != nil { + return nil, err + } + } + 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 tagExists(removedTagName, t) { + _, removedMajor, removedMinor, err = extractRemovedTag(t) + if err != nil { + return nil, err + } + } + a = a. + With("removedMajor", removedMajor). + With("removedMinor", removedMinor) + + 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.Infof("Generating prerelease-lifecycle for type %v", t) + + sw := generator.NewSnippetWriter(w, c, "$", "$") + args, err := argsFromType(t) + if err != nil { + return err + } + + if versionedMethodOrDie("Introduced", t) == nil { + sw.Do("// Introduced 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$) Introduced() (int64, int64) {\n", args) + sw.Do(" return $.introducedMajor$, $.introducedMinor$\n", args) + sw.Do("}\n\n", nil) + } + if versionedMethodOrDie("Deprecated", t) == nil { + sw.Do("// Deprecated 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$) Deprecated() (int64, int64) {\n", args) + sw.Do(" return $.deprecatedMajor$, $.deprecatedMinor$\n", args) + sw.Do("}\n\n", nil) + } + if versionedMethodOrDie("Removed", t) == nil { + sw.Do("// Removed 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$) Removed() (int64, int64) {\n", args) + sw.Do(" return $.removedMajor$, $.removedMinor$\n", args) + sw.Do("}\n\n", nil) + } + + return sw.Error() +}