k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/hack/update-codegen.sh (about) 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 18 set -o errexit 19 set -o nounset 20 set -o pipefail 21 22 # This tool wants a different default than usual. 23 KUBE_VERBOSE="${KUBE_VERBOSE:-1}" 24 25 KUBE_ROOT=$(dirname "${BASH_SOURCE[0]}")/.. 26 source "${KUBE_ROOT}/hack/lib/init.sh" 27 source "${KUBE_ROOT}/hack/lib/protoc.sh" 28 cd "${KUBE_ROOT}" 29 30 kube::golang::setup_env 31 32 DBG_CODEGEN="${DBG_CODEGEN:-0}" 33 GENERATED_FILE_PREFIX="${GENERATED_FILE_PREFIX:-zz_generated.}" 34 UPDATE_API_KNOWN_VIOLATIONS="${UPDATE_API_KNOWN_VIOLATIONS:-}" 35 API_KNOWN_VIOLATIONS_DIR="${API_KNOWN_VIOLATIONS_DIR:-"${KUBE_ROOT}/api/api-rules"}" 36 37 OUT_DIR="_output" 38 BOILERPLATE_FILENAME="hack/boilerplate/boilerplate.generatego.txt" 39 APPLYCONFIG_PKG="k8s.io/client-go/applyconfigurations" 40 PLURAL_EXCEPTIONS="Endpoints:Endpoints,ResourceClaimParameters:ResourceClaimParameters,ResourceClassParameters:ResourceClassParameters" 41 42 # Any time we call sort, we want it in the same locale. 43 export LC_ALL="C" 44 45 # Work around for older grep tools which might have options we don't want. 46 unset GREP_OPTIONS 47 48 if [[ "${DBG_CODEGEN}" == 1 ]]; then 49 kube::log::status "DBG: starting generated_files" 50 fi 51 52 # Generate a list of directories we don't want to play in. 53 DIRS_TO_AVOID=() 54 kube::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 61 function 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 68 function 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. 78 if [[ "${DBG_CODEGEN}" == 1 ]]; then 79 kube::log::status "DBG: finding all +k8s: tags" 80 fi 81 ALL_K8S_TAG_FILES=() 82 kube::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 ) 89 if [[ "${DBG_CODEGEN}" == 1 ]]; then 90 kube::log::status "DBG: found ${#ALL_K8S_TAG_FILES[@]} +k8s: tagged files" 91 fi 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. 101 function 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 147 function 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. 200 function 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. 229 EOF 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. 248 function 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 271 function 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 335 function 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. 404 function 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 462 function 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 482 function 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 560 function 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 602 function 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 656 function 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 696 function 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 739 function indent() { 740 while read -r X; do 741 echo " ${X}" 742 done 743 } 744 745 function 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 770 function 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 817 function 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 831 all_codegens=($(list_codegens)) 832 833 function 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. 842 flags_to_pass=() 843 codegens_to_run=() 844 for 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[@]}"}") 876 done 877 878 # If no codegens were specified, run them all. 879 if [[ "${#codegens_to_run[@]}" == 0 ]]; then 880 codegens_to_run=("${all_codegens[@]}") 881 fi 882 883 for 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[@]}"}" 886 done