...
1#!/usr/bin/env bash
2# Copyright 2014 The Kubernetes Authors.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16# shellcheck disable=2046 # printf word-splitting is intentional
17
18set -o errexit
19set -o nounset
20set -o pipefail
21
22# This tool wants a different default than usual.
23KUBE_VERBOSE="${KUBE_VERBOSE:-1}"
24
25KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/..
26source "${KUBE_ROOT}/hack/lib/init.sh"
27source "${KUBE_ROOT}/hack/lib/protoc.sh"
28cd "${KUBE_ROOT}"
29
30kube::golang::setup_env
31
32DBG_CODEGEN="${DBG_CODEGEN:-0}"
33GENERATED_FILE_PREFIX="${GENERATED_FILE_PREFIX:-zz_generated.}"
34UPDATE_API_KNOWN_VIOLATIONS="${UPDATE_API_KNOWN_VIOLATIONS:-}"
35API_KNOWN_VIOLATIONS_DIR="${API_KNOWN_VIOLATIONS_DIR:-"${KUBE_ROOT}/api/api-rules"}"
36
37OUT_DIR="_output"
38BOILERPLATE_FILENAME="hack/boilerplate/boilerplate.generatego.txt"
39APPLYCONFIG_PKG="k8s.io/client-go/applyconfigurations"
40PLURAL_EXCEPTIONS="Endpoints:Endpoints,ResourceClaimParameters:ResourceClaimParameters,ResourceClassParameters:ResourceClassParameters"
41
42# Any time we call sort, we want it in the same locale.
43export LC_ALL="C"
44
45# Work around for older grep tools which might have options we don't want.
46unset GREP_OPTIONS
47
48if [[ "${DBG_CODEGEN}" == 1 ]]; then
49 kube::log::status "DBG: starting generated_files"
50fi
51
52# Generate a list of directories we don't want to play in.
53DIRS_TO_AVOID=()
54kube::util::read-array DIRS_TO_AVOID < <(
55 git ls-files -cmo --exclude-standard -- ':!:vendor/*' ':(glob)*/**/go.work' \
56 | while read -r F; do \
57 echo ':!:'"$(dirname "${F}")"; \
58 done
59 )
60
61function git_find() {
62 # Similar to find but faster and easier to understand. We want to include
63 # modified and untracked files because this might be running against code
64 # which is not tracked by git yet.
65 git ls-files -cmo --exclude-standard ':!:vendor/*' "${DIRS_TO_AVOID[@]}" "$@"
66}
67
68function git_grep() {
69 # We want to include modified and untracked files because this might be
70 # running against code which is not tracked by git yet.
71 # We need vendor exclusion added at the end since it has to be part of
72 # the pathspecs which are specified last.
73 git grep --untracked "$@" ':!:vendor/*' "${DIRS_TO_AVOID[@]}"
74}
75
76# Generate a list of all files that have a `+k8s:` comment-tag. This will be
77# used to derive lists of files/dirs for generation tools.
78if [[ "${DBG_CODEGEN}" == 1 ]]; then
79 kube::log::status "DBG: finding all +k8s: tags"
80fi
81ALL_K8S_TAG_FILES=()
82kube::util::read-array ALL_K8S_TAG_FILES < <(
83 git_grep -l \
84 -e '^// *+k8s:' `# match +k8s: tags` \
85 -- \
86 ':!:*/testdata/*' `# not under any testdata` \
87 ':(glob)**/*.go' `# in any *.go file` \
88 )
89if [[ "${DBG_CODEGEN}" == 1 ]]; then
90 kube::log::status "DBG: found ${#ALL_K8S_TAG_FILES[@]} +k8s: tagged files"
91fi
92
93#
94# Code generation logic.
95#
96
97# protobuf generation
98#
99# Some of the later codegens depend on the results of this, so it needs to come
100# first in the case of regenerating everything.
101function codegen::protobuf() {
102 # NOTE: All output from this script needs to be copied back to the calling
103 # source tree. This is managed in kube::build::copy_output in build/common.sh.
104 # If the output set is changed update that function.
105
106 local apis=()
107 kube::util::read-array apis < <(
108 git grep --untracked --null -l \
109 -e '// +k8s:protobuf-gen=package' \
110 -- \
111 cmd pkg staging \
112 | while read -r -d $'\0' F; do dirname "${F}"; done \
113 | sed 's|^|k8s.io/kubernetes/|;s|k8s.io/kubernetes/staging/src/||' \
114 | sort -u)
115
116 kube::log::status "Generating protobufs for ${#apis[@]} targets"
117 if [[ "${DBG_CODEGEN}" == 1 ]]; then
118 kube::log::status "DBG: generating protobufs for:"
119 for dir in "${apis[@]}"; do
120 kube::log::status "DBG: $dir"
121 done
122 fi
123
124 git_find -z \
125 ':(glob)**/generated.proto' \
126 ':(glob)**/generated.pb.go' \
127 | xargs -0 rm -f
128
129 if kube::protoc::check_protoc >/dev/null; then
130 hack/_update-generated-protobuf-dockerized.sh "${apis[@]}"
131 else
132 kube::log::status "protoc ${PROTOC_VERSION} not found (can install with hack/install-protoc.sh); generating containerized..."
133 build/run.sh hack/_update-generated-protobuf-dockerized.sh "${apis[@]}"
134 fi
135}
136
137# Deep-copy generation
138#
139# Any package that wants deep-copy functions generated must include a
140# comment-tag in column 0 of one file of the form:
141# // +k8s:deepcopy-gen=<VALUE>
142#
143# The <VALUE> may be one of:
144# generate: generate deep-copy functions into the package
145# register: generate deep-copy functions and register them with a
146# scheme
147function codegen::deepcopy() {
148 # Build the tool.
149 GOPROXY=off go install \
150 k8s.io/code-generator/cmd/deepcopy-gen
151
152 # The result file, in each pkg, of deep-copy generation.
153 local output_file="${GENERATED_FILE_PREFIX}deepcopy.go"
154
155 # Find all the directories that request deep-copy generation.
156 if [[ "${DBG_CODEGEN}" == 1 ]]; then
157 kube::log::status "DBG: finding all +k8s:deepcopy-gen tags"
158 fi
159 local tag_dirs=()
160 kube::util::read-array tag_dirs < <( \
161 grep -l --null '+k8s:deepcopy-gen=' "${ALL_K8S_TAG_FILES[@]}" \
162 | while read -r -d $'\0' F; do dirname "${F}"; done \
163 | sort -u)
164 if [[ "${DBG_CODEGEN}" == 1 ]]; then
165 kube::log::status "DBG: found ${#tag_dirs[@]} +k8s:deepcopy-gen tagged dirs"
166 fi
167
168 local tag_pkgs=()
169 for dir in "${tag_dirs[@]}"; do
170 tag_pkgs+=("./$dir")
171 done
172
173 kube::log::status "Generating deepcopy code for ${#tag_pkgs[@]} targets"
174 if [[ "${DBG_CODEGEN}" == 1 ]]; then
175 kube::log::status "DBG: running deepcopy-gen for:"
176 for dir in "${tag_dirs[@]}"; do
177 kube::log::status "DBG: $dir"
178 done
179 fi
180
181 git_find -z ':(glob)**'/"${output_file}" | xargs -0 rm -f
182
183 deepcopy-gen \
184 -v "${KUBE_VERBOSE}" \
185 --go-header-file "${BOILERPLATE_FILENAME}" \
186 --output-file "${output_file}" \
187 --bounding-dirs "k8s.io/kubernetes,k8s.io/api" \
188 "${tag_pkgs[@]}" \
189 "$@"
190
191 if [[ "${DBG_CODEGEN}" == 1 ]]; then
192 kube::log::status "Generated deepcopy code"
193 fi
194}
195
196# Generates types_swagger_doc_generated file for the given group version.
197# $1: Name of the group version
198# $2: Path to the directory where types.go for that group version exists. This
199# is the directory where the file will be generated.
200function gen_types_swagger_doc() {
201 local group_version="$1"
202 local gv_dir="$2"
203 local tmpfile
204 tmpfile="${TMPDIR:-/tmp}/types_swagger_doc_generated.$(date +%s).go"
205
206 if [[ "${DBG_CODEGEN}" == 1 ]]; then
207 kube::log::status "DBG: running genswaggertypedocs for ${group_version} at ${gv_dir}"
208 fi
209
210 {
211 cat "${BOILERPLATE_FILENAME}"
212 echo
213 echo "package ${group_version##*/}"
214 # Indenting here prevents the boilerplate checker from thinking this file
215 # is generated - gofmt will fix the indents anyway.
216 cat <<EOF
217
218 // This file contains a collection of methods that can be used from go-restful to
219 // generate Swagger API documentation for its models. Please read this PR for more
220 // information on the implementation: https://github.com/emicklei/go-restful/pull/215
221 //
222 // TODOs are ignored from the parser (e.g. TODO(andronat):... || TODO:...) if and only if
223 // they are on one line! For multiple line or blocks that you want to ignore use ---.
224 // Any context after a --- is ignored.
225 //
226 // Those methods can be generated by using hack/update-codegen.sh
227
228 // AUTO-GENERATED FUNCTIONS START HERE. DO NOT EDIT.
229EOF
230 } > "${tmpfile}"
231
232 genswaggertypedocs \
233 -s \
234 "${gv_dir}/types.go" \
235 -f - \
236 >> "${tmpfile}"
237
238 echo "// AUTO-GENERATED FUNCTIONS END HERE" >> "${tmpfile}"
239
240 gofmt -w -s "${tmpfile}"
241 mv "${tmpfile}" "${gv_dir}/types_swagger_doc_generated.go"
242}
243
244# swagger generation
245#
246# Some of the later codegens depend on the results of this, so it needs to come
247# first in the case of regenerating everything.
248function codegen::swagger() {
249 # Build the tool
250 GOPROXY=off go install \
251 ./cmd/genswaggertypedocs
252
253 local group_versions=()
254 IFS=" " read -r -a group_versions <<< "meta/v1 meta/v1beta1 ${KUBE_AVAILABLE_GROUP_VERSIONS}"
255
256 kube::log::status "Generating swagger for ${#group_versions[@]} targets"
257
258 git_find -z ':(glob)**/types_swagger_doc_generated.go' | xargs -0 rm -f
259
260 # Regenerate files.
261 for group_version in "${group_versions[@]}"; do
262 gen_types_swagger_doc "${group_version}" "$(kube::util::group-version-to-pkg-path "${group_version}")"
263 done
264}
265
266# prerelease-lifecycle generation
267#
268# Any package that wants prerelease-lifecycle functions generated must include a
269# comment-tag in column 0 of one file of the form:
270# // +k8s:prerelease-lifecycle-gen=true
271function codegen::prerelease() {
272 # Build the tool.
273 GOPROXY=off go install \
274 k8s.io/code-generator/cmd/prerelease-lifecycle-gen
275
276 # The result file, in each pkg, of prerelease-lifecycle generation.
277 local output_file="${GENERATED_FILE_PREFIX}prerelease-lifecycle.go"
278
279 # Find all the directories that request prerelease-lifecycle generation.
280 if [[ "${DBG_CODEGEN}" == 1 ]]; then
281 kube::log::status "DBG: finding all +k8s:prerelease-lifecycle-gen tags"
282 fi
283 local tag_dirs=()
284 kube::util::read-array tag_dirs < <( \
285 grep -l --null '+k8s:prerelease-lifecycle-gen=true' "${ALL_K8S_TAG_FILES[@]}" \
286 | while read -r -d $'\0' F; do dirname "${F}"; done \
287 | sort -u)
288 if [[ "${DBG_CODEGEN}" == 1 ]]; then
289 kube::log::status "DBG: found ${#tag_dirs[@]} +k8s:prerelease-lifecycle-gen tagged dirs"
290 fi
291
292 local tag_pkgs=()
293 for dir in "${tag_dirs[@]}"; do
294 tag_pkgs+=("./$dir")
295 done
296
297 kube::log::status "Generating prerelease-lifecycle code for ${#tag_pkgs[@]} targets"
298 if [[ "${DBG_CODEGEN}" == 1 ]]; then
299 kube::log::status "DBG: running prerelease-lifecycle-gen for:"
300 for dir in "${tag_dirs[@]}"; do
301 kube::log::status "DBG: $dir"
302 done
303 fi
304
305 git_find -z ':(glob)**'/"${output_file}" | xargs -0 rm -f
306
307 prerelease-lifecycle-gen \
308 -v "${KUBE_VERBOSE}" \
309 --go-header-file "${BOILERPLATE_FILENAME}" \
310 --output-file "${output_file}" \
311 "${tag_pkgs[@]}" \
312 "$@"
313
314 if [[ "${DBG_CODEGEN}" == 1 ]]; then
315 kube::log::status "Generated prerelease-lifecycle code"
316 fi
317}
318
319# Defaulter generation
320#
321# Any package that wants defaulter functions generated must include a
322# comment-tag in column 0 of one file of the form:
323# // +k8s:defaulter-gen=<VALUE>
324#
325# The <VALUE> depends on context:
326# on types:
327# true: always generate a defaulter for this type
328# false: never generate a defaulter for this type
329# on functions:
330# covers: if the function name matches SetDefault_NAME, instructs
331# the generator not to recurse
332# on packages:
333# FIELDNAME: any object with a field of this name is a candidate
334# for having a defaulter generated
335function codegen::defaults() {
336 # Build the tool.
337 GOPROXY=off go install \
338 k8s.io/code-generator/cmd/defaulter-gen
339
340 # The result file, in each pkg, of defaulter generation.
341 local output_file="${GENERATED_FILE_PREFIX}defaults.go"
342
343 # All directories that request any form of defaulter generation.
344 if [[ "${DBG_CODEGEN}" == 1 ]]; then
345 kube::log::status "DBG: finding all +k8s:defaulter-gen tags"
346 fi
347 local tag_dirs=()
348 kube::util::read-array tag_dirs < <( \
349 grep -l --null '+k8s:defaulter-gen=' "${ALL_K8S_TAG_FILES[@]}" \
350 | while read -r -d $'\0' F; do dirname "${F}"; done \
351 | sort -u)
352 if [[ "${DBG_CODEGEN}" == 1 ]]; then
353 kube::log::status "DBG: found ${#tag_dirs[@]} +k8s:defaulter-gen tagged dirs"
354 fi
355
356 local tag_pkgs=()
357 for dir in "${tag_dirs[@]}"; do
358 tag_pkgs+=("./$dir")
359 done
360
361 kube::log::status "Generating defaulter code for ${#tag_pkgs[@]} targets"
362 if [[ "${DBG_CODEGEN}" == 1 ]]; then
363 kube::log::status "DBG: running defaulter-gen for:"
364 for dir in "${tag_dirs[@]}"; do
365 kube::log::status "DBG: $dir"
366 done
367 fi
368
369 git_find -z ':(glob)**'/"${output_file}" | xargs -0 rm -f
370
371 defaulter-gen \
372 -v "${KUBE_VERBOSE}" \
373 --go-header-file "${BOILERPLATE_FILENAME}" \
374 --output-file "${output_file}" \
375 "${tag_pkgs[@]}" \
376 "$@"
377
378 if [[ "${DBG_CODEGEN}" == 1 ]]; then
379 kube::log::status "Generated defaulter code"
380 fi
381}
382
383# Conversion generation
384
385# Any package that wants conversion functions generated into it must
386# include one or more comment-tags in its `doc.go` file, of the form:
387# // +k8s:conversion-gen=<INTERNAL_TYPES_DIR>
388#
389# The INTERNAL_TYPES_DIR is a project-local path to another directory
390# which should be considered when evaluating peer types for
391# conversions. An optional additional comment of the form
392# // +k8s:conversion-gen-external-types=<EXTERNAL_TYPES_DIR>
393#
394# identifies where to find the external types; if there is no such
395# comment then the external types are sought in the package where the
396# `k8s:conversion` tag is found.
397#
398# Conversions, in both directions, are generated for every type name
399# that is defined in both an internal types package and the external
400# types package.
401#
402# TODO: it might be better in the long term to make peer-types explicit in the
403# IDL.
404function codegen::conversions() {
405 # Build the tool.
406 GOPROXY=off go install \
407 k8s.io/code-generator/cmd/conversion-gen
408
409 # The result file, in each pkg, of conversion generation.
410 local output_file="${GENERATED_FILE_PREFIX}conversion.go"
411
412 # All directories that request any form of conversion generation.
413 if [[ "${DBG_CODEGEN}" == 1 ]]; then
414 kube::log::status "DBG: finding all +k8s:conversion-gen tags"
415 fi
416 local tag_dirs=()
417 kube::util::read-array tag_dirs < <(\
418 grep -l --null '^// *+k8s:conversion-gen=' "${ALL_K8S_TAG_FILES[@]}" \
419 | while read -r -d $'\0' F; do dirname "${F}"; done \
420 | sort -u)
421 if [[ "${DBG_CODEGEN}" == 1 ]]; then
422 kube::log::status "DBG: found ${#tag_dirs[@]} +k8s:conversion-gen tagged dirs"
423 fi
424
425 local tag_pkgs=()
426 for dir in "${tag_dirs[@]}"; do
427 tag_pkgs+=("./$dir")
428 done
429
430 local extra_peer_pkgs=(
431 k8s.io/kubernetes/pkg/apis/core
432 k8s.io/kubernetes/pkg/apis/core/v1
433 k8s.io/api/core/v1
434 )
435
436 kube::log::status "Generating conversion code for ${#tag_pkgs[@]} targets"
437 if [[ "${DBG_CODEGEN}" == 1 ]]; then
438 kube::log::status "DBG: running conversion-gen for:"
439 for dir in "${tag_dirs[@]}"; do
440 kube::log::status "DBG: $dir"
441 done
442 fi
443
444 git_find -z ':(glob)**'/"${output_file}" | xargs -0 rm -f
445
446 conversion-gen \
447 -v "${KUBE_VERBOSE}" \
448 --go-header-file "${BOILERPLATE_FILENAME}" \
449 --output-file "${output_file}" \
450 $(printf -- " --extra-peer-dirs %s" "${extra_peer_pkgs[@]}") \
451 "${tag_pkgs[@]}" \
452 "$@"
453
454 if [[ "${DBG_CODEGEN}" == 1 ]]; then
455 kube::log::status "Generated conversion code"
456 fi
457}
458
459# $@: directories to exclude
460# example:
461# k8s_tag_files_except foo bat/qux
462function k8s_tag_files_except() {
463 for f in "${ALL_K8S_TAG_FILES[@]}"; do
464 local excl=""
465 for x in "$@"; do
466 if [[ "$f" =~ "$x"/.* ]]; then
467 excl="true"
468 break
469 fi
470 done
471 if [[ "${excl}" != true ]]; then
472 echo "$f"
473 fi
474 done
475}
476
477# OpenAPI generation
478#
479# Any package that wants open-api functions generated must include a
480# comment-tag in column 0 of one file of the form:
481# // +k8s:openapi-gen=true
482function codegen::openapi() {
483 # Build the tool.
484 GOPROXY=off go install \
485 k8s.io/kube-openapi/cmd/openapi-gen
486
487 # The result file, in each pkg, of open-api generation.
488 local output_file="${GENERATED_FILE_PREFIX}openapi.go"
489
490 local output_dir="pkg/generated/openapi"
491 local output_pkg="k8s.io/kubernetes/${output_dir}"
492 local known_violations_file="${API_KNOWN_VIOLATIONS_DIR}/violation_exceptions.list"
493
494 local report_file="${OUT_DIR}/api_violations.report"
495 # When UPDATE_API_KNOWN_VIOLATIONS is set to be true, let the generator to write
496 # updated API violations to the known API violation exceptions list.
497 if [[ "${UPDATE_API_KNOWN_VIOLATIONS}" == true ]]; then
498 report_file="${known_violations_file}"
499 fi
500
501 if [[ "${DBG_CODEGEN}" == 1 ]]; then
502 kube::log::status "DBG: finding all +k8s:openapi-gen tags"
503 fi
504
505 local tag_files=()
506 kube::util::read-array tag_files < <(
507 k8s_tag_files_except \
508 staging/src/k8s.io/code-generator \
509 staging/src/k8s.io/sample-apiserver
510 )
511
512 local tag_dirs=()
513 kube::util::read-array tag_dirs < <(
514 grep -l --null '+k8s:openapi-gen=' "${tag_files[@]}" \
515 | while read -r -d $'\0' F; do dirname "${F}"; done \
516 | sort -u)
517
518 if [[ "${DBG_CODEGEN}" == 1 ]]; then
519 kube::log::status "DBG: found ${#tag_dirs[@]} +k8s:openapi-gen tagged dirs"
520 fi
521
522 local tag_pkgs=()
523 for dir in "${tag_dirs[@]}"; do
524 tag_pkgs+=("./$dir")
525 done
526
527 kube::log::status "Generating openapi code"
528 if [[ "${DBG_CODEGEN}" == 1 ]]; then
529 kube::log::status "DBG: running openapi-gen for:"
530 for dir in "${tag_dirs[@]}"; do
531 kube::log::status "DBG: $dir"
532 done
533 fi
534
535 git_find -z ':(glob)pkg/generated/**'/"${output_file}" | xargs -0 rm -f
536
537 openapi-gen \
538 -v "${KUBE_VERBOSE}" \
539 --go-header-file "${BOILERPLATE_FILENAME}" \
540 --output-file "${output_file}" \
541 --output-dir "${output_dir}" \
542 --output-pkg "${output_pkg}" \
543 --report-filename "${report_file}" \
544 "${tag_pkgs[@]}" \
545 "$@"
546
547 touch "${report_file}"
548 local known_filename="${known_violations_file}"
549 if ! diff -u "${known_filename}" "${report_file}"; then
550 echo -e "ERROR:"
551 echo -e "\tAPI rule check failed - reported violations differ from known violations"
552 echo -e "\tPlease read api/api-rules/README.md to resolve the failure in ${known_filename}"
553 fi
554
555 if [[ "${DBG_CODEGEN}" == 1 ]]; then
556 kube::log::status "Generated openapi code"
557 fi
558}
559
560function codegen::applyconfigs() {
561 GOPROXY=off go install \
562 k8s.io/kubernetes/pkg/generated/openapi/cmd/models-schema \
563 k8s.io/code-generator/cmd/applyconfiguration-gen
564
565 local ext_apis=()
566 kube::util::read-array ext_apis < <(
567 cd "${KUBE_ROOT}/staging/src"
568 git_find -z ':(glob)k8s.io/api/**/types.go' \
569 | while read -r -d $'\0' F; do dirname "${F}"; done \
570 | sort -u)
571 ext_apis+=("k8s.io/apimachinery/pkg/apis/meta/v1")
572
573 kube::log::status "Generating apply-config code for ${#ext_apis[@]} targets"
574 if [[ "${DBG_CODEGEN}" == 1 ]]; then
575 kube::log::status "DBG: running applyconfiguration-gen for:"
576 for api in "${ext_apis[@]}"; do
577 kube::log::status "DBG: $api"
578 done
579 fi
580
581 (git_grep -l --null \
582 -e '^// Code generated by applyconfiguration-gen. DO NOT EDIT.$' \
583 -- \
584 ':(glob)staging/src/k8s.io/client-go/**/*.go' \
585 || true) \
586 | xargs -0 rm -f
587
588 applyconfiguration-gen \
589 -v "${KUBE_VERBOSE}" \
590 --openapi-schema <(models-schema) \
591 --go-header-file "${BOILERPLATE_FILENAME}" \
592 --output-dir "${KUBE_ROOT}/staging/src/${APPLYCONFIG_PKG}" \
593 --output-pkg "${APPLYCONFIG_PKG}" \
594 "${ext_apis[@]}" \
595 "$@"
596
597 if [[ "${DBG_CODEGEN}" == 1 ]]; then
598 kube::log::status "Generated apply-config code"
599 fi
600}
601
602function codegen::clients() {
603 GOPROXY=off go install \
604 k8s.io/code-generator/cmd/client-gen
605
606 IFS=" " read -r -a group_versions <<< "${KUBE_AVAILABLE_GROUP_VERSIONS}"
607 local gv_dirs=()
608 for gv in "${group_versions[@]}"; do
609 # add items, but strip off any leading apis/ you find to match command expectations
610 local api_dir
611 api_dir=$(kube::util::group-version-to-pkg-path "${gv}")
612 local nopkg_dir=${api_dir#pkg/}
613 nopkg_dir=${nopkg_dir#staging/src/k8s.io/api/}
614 local pkg_dir=${nopkg_dir#apis/}
615
616 # skip groups that aren't being served, clients for these don't matter
617 if [[ " ${KUBE_NONSERVER_GROUP_VERSIONS} " == *" ${gv} "* ]]; then
618 continue
619 fi
620
621 gv_dirs+=("${pkg_dir}")
622 done
623
624 kube::log::status "Generating client code for ${#gv_dirs[@]} targets"
625 if [[ "${DBG_CODEGEN}" == 1 ]]; then
626 kube::log::status "DBG: running client-gen for:"
627 for dir in "${gv_dirs[@]}"; do
628 kube::log::status "DBG: $dir"
629 done
630 fi
631
632 (git_grep -l --null \
633 -e '^// Code generated by client-gen. DO NOT EDIT.$' \
634 -- \
635 ':(glob)staging/src/k8s.io/client-go/**/*.go' \
636 || true) \
637 | xargs -0 rm -f
638
639 client-gen \
640 -v "${KUBE_VERBOSE}" \
641 --go-header-file "${BOILERPLATE_FILENAME}" \
642 --output-dir "${KUBE_ROOT}/staging/src/k8s.io/client-go" \
643 --output-pkg="k8s.io/client-go" \
644 --clientset-name="kubernetes" \
645 --input-base="k8s.io/api" \
646 --plural-exceptions "${PLURAL_EXCEPTIONS}" \
647 --apply-configuration-package "${APPLYCONFIG_PKG}" \
648 $(printf -- " --input %s" "${gv_dirs[@]}") \
649 "$@"
650
651 if [[ "${DBG_CODEGEN}" == 1 ]]; then
652 kube::log::status "Generated client code"
653 fi
654}
655
656function codegen::listers() {
657 GOPROXY=off go install \
658 k8s.io/code-generator/cmd/lister-gen
659
660 local ext_apis=()
661 kube::util::read-array ext_apis < <(
662 cd "${KUBE_ROOT}/staging/src"
663 git_find -z ':(glob)k8s.io/api/**/types.go' \
664 | while read -r -d $'\0' F; do dirname "${F}"; done \
665 | sort -u)
666
667 kube::log::status "Generating lister code for ${#ext_apis[@]} targets"
668 if [[ "${DBG_CODEGEN}" == 1 ]]; then
669 kube::log::status "DBG: running lister-gen for:"
670 for api in "${ext_apis[@]}"; do
671 kube::log::status "DBG: $api"
672 done
673 fi
674
675 (git_grep -l --null \
676 -e '^// Code generated by lister-gen. DO NOT EDIT.$' \
677 -- \
678 ':(glob)staging/src/k8s.io/client-go/**/*.go' \
679 || true) \
680 | xargs -0 rm -f
681
682 lister-gen \
683 -v "${KUBE_VERBOSE}" \
684 --go-header-file "${BOILERPLATE_FILENAME}" \
685 --output-dir "${KUBE_ROOT}/staging/src/k8s.io/client-go/listers" \
686 --output-pkg "k8s.io/client-go/listers" \
687 --plural-exceptions "${PLURAL_EXCEPTIONS}" \
688 "${ext_apis[@]}" \
689 "$@"
690
691 if [[ "${DBG_CODEGEN}" == 1 ]]; then
692 kube::log::status "Generated lister code"
693 fi
694}
695
696function codegen::informers() {
697 GOPROXY=off go install \
698 k8s.io/code-generator/cmd/informer-gen
699
700 local ext_apis=()
701 kube::util::read-array ext_apis < <(
702 cd "${KUBE_ROOT}/staging/src"
703 git_find -z ':(glob)k8s.io/api/**/types.go' \
704 | while read -r -d $'\0' F; do dirname "${F}"; done \
705 | sort -u)
706
707 kube::log::status "Generating informer code for ${#ext_apis[@]} targets"
708 if [[ "${DBG_CODEGEN}" == 1 ]]; then
709 kube::log::status "DBG: running informer-gen for:"
710 for api in "${ext_apis[@]}"; do
711 kube::log::status "DBG: $api"
712 done
713 fi
714
715 (git_grep -l --null \
716 -e '^// Code generated by informer-gen. DO NOT EDIT.$' \
717 -- \
718 ':(glob)staging/src/k8s.io/client-go/**/*.go' \
719 || true) \
720 | xargs -0 rm -f
721
722 informer-gen \
723 -v "${KUBE_VERBOSE}" \
724 --go-header-file "${BOILERPLATE_FILENAME}" \
725 --output-dir "${KUBE_ROOT}/staging/src/k8s.io/client-go/informers" \
726 --output-pkg "k8s.io/client-go/informers" \
727 --single-directory \
728 --versioned-clientset-package "k8s.io/client-go/kubernetes" \
729 --listers-package "k8s.io/client-go/listers" \
730 --plural-exceptions "${PLURAL_EXCEPTIONS}" \
731 "${ext_apis[@]}" \
732 "$@"
733
734 if [[ "${DBG_CODEGEN}" == 1 ]]; then
735 kube::log::status "Generated informer code"
736 fi
737}
738
739function indent() {
740 while read -r X; do
741 echo " ${X}"
742 done
743}
744
745function codegen::subprojects() {
746 # Call generation on sub-projects.
747 local subs=(
748 staging/src/k8s.io/code-generator/examples
749 staging/src/k8s.io/kube-aggregator
750 staging/src/k8s.io/sample-apiserver
751 staging/src/k8s.io/sample-controller
752 staging/src/k8s.io/metrics
753 staging/src/k8s.io/apiextensions-apiserver
754 staging/src/k8s.io/apiextensions-apiserver/examples/client-go
755 )
756
757 local codegen
758 codegen="${KUBE_ROOT}/staging/src/k8s.io/code-generator"
759 for sub in "${subs[@]}"; do
760 kube::log::status "Generating code for subproject ${sub}"
761 pushd "${sub}" >/dev/null
762 CODEGEN_PKG="${codegen}" \
763 UPDATE_API_KNOWN_VIOLATIONS="${UPDATE_API_KNOWN_VIOLATIONS}" \
764 API_KNOWN_VIOLATIONS_DIR="${API_KNOWN_VIOLATIONS_DIR}" \
765 ./hack/update-codegen.sh > >(indent) 2> >(indent >&2)
766 popd >/dev/null
767 done
768}
769
770function codegen::protobindings() {
771 # Each element of this array is a directory containing subdirectories which
772 # eventually contain a file named "api.proto".
773 local apis=(
774 "staging/src/k8s.io/cri-api/pkg/apis/runtime"
775
776 "staging/src/k8s.io/kubelet/pkg/apis/podresources"
777
778 "staging/src/k8s.io/kubelet/pkg/apis/deviceplugin"
779
780 "staging/src/k8s.io/kms/apis"
781 "staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2"
782
783 "staging/src/k8s.io/kubelet/pkg/apis/dra"
784
785 "staging/src/k8s.io/kubelet/pkg/apis/pluginregistration"
786 "pkg/kubelet/pluginmanager/pluginwatcher/example_plugin_apis"
787 )
788
789 kube::log::status "Generating protobuf bindings for ${#apis[@]} targets"
790 if [[ "${DBG_CODEGEN}" == 1 ]]; then
791 kube::log::status "DBG: generating protobuf bindings for:"
792 for dir in "${apis[@]}"; do
793 kube::log::status "DBG: $dir"
794 done
795 fi
796
797 for api in "${apis[@]}"; do
798 git_find -z ":(glob)${api}"/'**/api.pb.go' \
799 | xargs -0 rm -f
800 done
801
802 if kube::protoc::check_protoc >/dev/null; then
803 hack/_update-generated-proto-bindings-dockerized.sh "${apis[@]}"
804 else
805 kube::log::status "protoc ${PROTOC_VERSION} not found (can install with hack/install-protoc.sh); generating containerized..."
806 # NOTE: All output from this script needs to be copied back to the calling
807 # source tree. This is managed in kube::build::copy_output in build/common.sh.
808 # If the output set is changed update that function.
809 build/run.sh hack/_update-generated-proto-bindings-dockerized.sh "${apis[@]}"
810 fi
811}
812
813#
814# main
815#
816
817function list_codegens() {
818 (
819 shopt -s extdebug
820 declare -F \
821 | cut -f3 -d' ' \
822 | grep "^codegen::" \
823 | while read -r fn; do declare -F "$fn"; done \
824 | sort -n -k2 \
825 | cut -f1 -d' ' \
826 | sed 's/^codegen:://'
827 )
828}
829
830# shellcheck disable=SC2207 # safe, no functions have spaces
831all_codegens=($(list_codegens))
832
833function print_codegens() {
834 echo "available codegens:"
835 for g in "${all_codegens[@]}"; do
836 echo " $g"
837 done
838}
839
840# Validate and accumulate flags to pass thru and codegens to run if args are
841# specified.
842flags_to_pass=()
843codegens_to_run=()
844for arg; do
845 # Use -? to list known codegens.
846 if [[ "${arg}" == "-?" ]]; then
847 print_codegens
848 exit 0
849 fi
850 if [[ "${arg}" =~ ^- ]]; then
851 flags_to_pass+=("${arg}")
852 continue
853 fi
854 # Make sure each non-flag arg matches at least one codegen.
855 nmatches=0
856 for t in "${all_codegens[@]}"; do
857 if [[ "$t" =~ ${arg} ]]; then
858 nmatches=$((nmatches+1))
859 # Don't run codegens twice, just keep the first match.
860 # shellcheck disable=SC2076 # we want literal matching
861 if [[ " ${codegens_to_run[*]} " =~ " $t " ]]; then
862 continue
863 fi
864 codegens_to_run+=("$t")
865 continue
866 fi
867 done
868 if [[ ${nmatches} == 0 ]]; then
869 echo "ERROR: no codegens match pattern '${arg}'"
870 echo
871 print_codegens
872 exit 1
873 fi
874 # The array-syntax abomination is to accommodate older bash.
875 codegens_to_run+=("${matches[@]:+"${matches[@]}"}")
876done
877
878# If no codegens were specified, run them all.
879if [[ "${#codegens_to_run[@]}" == 0 ]]; then
880 codegens_to_run=("${all_codegens[@]}")
881fi
882
883for g in "${codegens_to_run[@]}"; do
884 # The array-syntax abomination is to accommodate older bash.
885 "codegen::${g}" "${flags_to_pass[@]:+"${flags_to_pass[@]}"}"
886done
View as plain text