#!/usr/bin/env bash

# Copyright 2020 the Pinniped contributors. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
KUBE_VERSIONS=("$@")
BASE_PKG="go.pinniped.dev"
export GO111MODULE="on"

# If we're not running in a container, assume that we want to loop over and run each build
# in a container.
if [[ -z "${CONTAINED:-}" ]]; then
    for kubeVersion in "${KUBE_VERSIONS[@]}"; do
        # CODEGEN_IMAGE is the container image to use when running
        CODEGEN_IMAGE="docker.io/getpinniped/k8s-code-generator-$(echo "$kubeVersion" | cut -d"." -f1-2):latest"

        echo "generating code for ${kubeVersion} using ${CODEGEN_IMAGE}..."
        docker run --rm \
            --env CONTAINED=1 \
            --volume "${ROOT}:/work" \
            --workdir "/work" \
            "${CODEGEN_IMAGE}" \
            "/work/hack/lib/$(basename "${BASH_SOURCE[0]}")" \
            "${kubeVersion}" \
            | sed "s|^|${kubeVersion} > |"
    done
    exit 0
fi

# Now that we know we are running in the nested container, expect there to be only
# a single Kubernetes version
if [[ "${#KUBE_VERSIONS[@]}" -ne 1 ]]; then
    echo "when running in a container, we can only generate for a single kubernetes version" >&2
    exit 1
fi

# Link the root directory into GOPATH since that is where output ends up.
GOPATH_ROOT="${GOPATH}/src/${BASE_PKG}"
mkdir -p "$(dirname "${GOPATH_ROOT}")"
ln -s "${ROOT}" "${GOPATH_ROOT}"
ROOT="${GOPATH_ROOT}"
cd "${ROOT}"

# KUBE_VERSION is the full version (e.g., '1.19.0-rc.0').
KUBE_VERSION="${KUBE_VERSIONS[0]}"
export KUBE_VERSION

# KUBE_MINOR_VERSION is just the major/minor version (e.g., '1.19').
KUBE_MINOR_VERSION="$(echo "${KUBE_VERSION}" | cut -d"." -f1-2)"
export KUBE_MINOR_VERSION

# KUBE_MODULE_VERSION is just version of client libraries (e.g., 'v0.19.9-rc-0').
KUBE_MODULE_VERSION="v0.$(echo "${KUBE_VERSION}" | cut -d '.' -f 2-)"
export KUBE_MODULE_VERSION

# Start by picking an output directory and deleting any previously-generated code.
OUTPUT_DIR="${ROOT}/generated/${KUBE_MINOR_VERSION}"
rm -rf "${OUTPUT_DIR}"
mkdir -p "${OUTPUT_DIR}"
cd "${OUTPUT_DIR}"

echo "running in container to generate ${KUBE_VERSION} into ${OUTPUT_DIR}..."

# Next, copy in the base definitions of our APIs from ./apis into the generated directory, substituting some
# variables in the template files and renaming them to strip the `.tmpl` extension.
cp -R "${ROOT}/apis" "${OUTPUT_DIR}/apis"
find "${OUTPUT_DIR}" -type f -exec sed -i "s|GENERATED_PKG|generated/${KUBE_MINOR_VERSION}|g" {} \;
find "${OUTPUT_DIR}" -type f -not -name '*.tmpl' -exec rm {} \;
find "${OUTPUT_DIR}" -type f -name '*.tmpl' -exec bash -c 'mv "$0" "${0%.tmpl}"' {} \;

# Make the generated API code its own Go module.
echo "generating ${OUTPUT_DIR}/apis/go.mod..."
cat << EOF > "${OUTPUT_DIR}/apis/go.mod"
// This go.mod file is generated by ./hack/codegen.sh.
module ${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis

go 1.13

require (
    k8s.io/apimachinery ${KUBE_MODULE_VERSION}
    k8s.io/api ${KUBE_MODULE_VERSION}
)
EOF

# Make the generated client code its own Go module.
echo "generating ${OUTPUT_DIR}/client/go.mod..."
mkdir client
mkdir client/concierge
mkdir client/supervisor
cat << EOF > "./client/go.mod"
// This go.mod file is generated by ./hack/codegen.sh.
module ${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/client

go 1.13

require (
    github.com/go-openapi/spec v0.19.9
    k8s.io/api ${KUBE_MODULE_VERSION}
    k8s.io/apimachinery ${KUBE_MODULE_VERSION}
    k8s.io/client-go ${KUBE_MODULE_VERSION}
    k8s.io/apimachinery ${KUBE_MODULE_VERSION}
)

replace ${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis => ../apis
EOF

# Generate API-related code for our public API groups
echo "generating API-related code for our public API groups..."
(cd apis &&
    bash "${GOPATH}/src/k8s.io/code-generator/generate-groups.sh" \
        deepcopy \
        "${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis" \
        "${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis" \
        "supervisor/config:v1alpha1 supervisor/idp:v1alpha1 concierge/config:v1alpha1 concierge/authentication:v1alpha1 concierge/login:v1alpha1" \
        --go-header-file "${ROOT}/hack/boilerplate.go.txt" 2>&1 | sed "s|^|gen-api > |"
)

# Generate API-related code for our internal API groups
echo "generating API-related code for our internal API groups..."
(cd apis &&
    bash "${GOPATH}/src/k8s.io/code-generator/generate-internal-groups.sh" \
        deepcopy,defaulter,conversion,openapi \
        "${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/client/concierge" \
        "${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis" \
        "${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis" \
        "concierge/login:v1alpha1" \
        --go-header-file "${ROOT}/hack/boilerplate.go.txt"  2>&1 | sed "s|^|gen-int-api > |"
)


# Tidy up the .../apis module
echo "tidying ${OUTPUT_DIR}/apis/go.mod..."
(cd apis && go mod tidy 2>&1 | sed "s|^|go-mod-tidy > |")

# Generate client code for our public API groups
echo "generating client code for our public API groups..."
(cd client &&
    bash "${GOPATH}/src/k8s.io/code-generator/generate-groups.sh" \
        client,lister,informer \
        "${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/client/concierge" \
        "${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis" \
        "concierge/config:v1alpha1 concierge/authentication:v1alpha1 concierge/login:v1alpha1" \
        --go-header-file "${ROOT}/hack/boilerplate.go.txt"  2>&1 | sed "s|^|gen-client > |"
)
  (cd client &&
    bash "${GOPATH}/src/k8s.io/code-generator/generate-groups.sh" \
        client,lister,informer \
        "${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/client/supervisor" \
        "${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis" \
        "supervisor/config:v1alpha1 supervisor/idp:v1alpha1" \
        --go-header-file "${ROOT}/hack/boilerplate.go.txt"  2>&1 | sed "s|^|gen-client > |"
)

# Tidy up the .../client module
echo "tidying ${OUTPUT_DIR}/client/go.mod..."
(cd client && go mod tidy 2>&1 | sed "s|^|go-mod-tidy > |")

# Generate API documentation
sed "s|KUBE_MINOR_VERSION|${KUBE_MINOR_VERSION}|g" < "${ROOT}/hack/lib/docs/config.yaml" > /tmp/docs-config.yaml
crd-ref-docs \
    --source-path="${ROOT}/generated/${KUBE_MINOR_VERSION}/apis" \
    --config=/tmp/docs-config.yaml \
    --renderer=asciidoctor \
    --templates-dir="${ROOT}/hack/lib/docs/templates" \
    --output-path="${ROOT}/generated/${KUBE_MINOR_VERSION}/README.adoc"

# Generate CRD YAML
(cd apis &&
    controller-gen paths=./supervisor/config/v1alpha1 crd:trivialVersions=true output:crd:artifacts:config=../crds &&
    controller-gen paths=./supervisor/idp/v1alpha1 crd:trivialVersions=true output:crd:artifacts:config=../crds &&
    controller-gen paths=./concierge/config/v1alpha1 crd:trivialVersions=true output:crd:artifacts:config=../crds &&
    controller-gen paths=./concierge/authentication/v1alpha1 crd:trivialVersions=true output:crd:artifacts:config=../crds
)
