...

Text file src/k8s.io/kubernetes/hack/update-codegen.sh

Documentation: k8s.io/kubernetes/hack

     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