#!/usr/bin/env bash
set -eux

# Add here the releases that we want to scan in the format 'vX.Y'.
RELEASES=("v2.7" "v2.7.16" "v2.8" "v2.8.9" "v2.9" "v2.9.3")

# These are global variables set inside parse_release().
RANCHER_RELEASE=""
CHARTS_RELEASE=""
RANCHER_IMAGE_VERSION=""
RELEASE=true

# File that contains Harvester's standalone images.
HARVESTER_IMAGES="images-sources-harvester-standalone.txt"
# File that contains Longhorn's standalone images.
LONGHORN_IMAGES="images-sources-longhorn-standalone.txt"
# File that contains RKE2's standalone images.
RKE2_IMAGES="images-sources-rke2-standalone.txt"

remove_rancher_dir() {
    if [ -d "./rancher" ]; then
        rm -rf ./rancher
    fi
}

# This function does a simple regex to determine if we are scanning a released version (e.g., v2.7.0)
# or a development branch (e.g., release/v2.7). Then, it will adjust the corresponding global variables
# to the correct Git branches used in rancher/rancher repo and the charts repos and also the container
# image version.
parse_release() {
    local release=$1
    local release_regex="^v[0-9]+\.[0-9]+\.[0-9]+$"
    local dev_head_release="^v[0-9]+\.[0-9]+$"

    if (echo "${release}" | grep -qE "${release_regex}"); then
        RANCHER_RELEASE="${release}"
        RANCHER_IMAGE_VERSION="${release}"
        RELEASE=true
    elif (echo "${release}" | grep -qE "${dev_head_release}"); then
        RANCHER_RELEASE="release/${release}"
        CHARTS_RELEASE="dev-${release}"
        RANCHER_IMAGE_VERSION="${release}-head"
        RELEASE=false
    else
        RANCHER_RELEASE=""
        CHARTS_RELEASE=""
        RANCHER_IMAGE_VERSION=""
        return 1
    fi

    return 0
}

generate_images() {
    local release="${1}"
    local charts="${2}"
    local image="${3}"

    git clone https://github.com/rancher/rancher
    git clone https://github.com/rancher/system-charts ./rancher/system-charts
    git clone https://github.com/rancher/charts ./rancher/charts

    cd rancher && git fetch && git checkout "${release}"
    cd system-charts && git fetch && git checkout origin/"${charts}" && cd ..
    cd charts && git fetch && git checkout origin/"${charts}" && cd ..

    mkdir bin
    curl https://raw.githubusercontent.com/rancher/kontainer-driver-metadata/"${charts}"/data/data.json -o bin/data.json

    # This is necessary in order to properly source the versions of images
    # that are owned/used by Rancher, but are developed outside of
    # the rancher/rancher repo.
    # For more context, please see the issue
    # https://github.com/rancher/image-scanning/issues/232 .
    # The following environment variables will be sourced:
    # - WINS_AGENT_UPGRADE_IMAGE
    # - SYSTEM_AGENT_UPGRADE_IMAGE
    # - SYSTEM_AGENT_INSTALLER_RKE2_IMAGES
    # - SYSTEM_AGENT_INSTALLER_K3S_IMAGES
    source ../image-versions.sh

    # This is only required because we still use Go 1.20 in release/v2.8 and
    # we use Go 1.21 in this automation.
    # Starting with Go 1.21 (source: https://tip.golang.org/doc/go1.21):
    #   "To improve forwards compatibility, Go 1.21 now reads the go line in
    #   a go.work or go.mod file as a strict minimum requirement: go 1.21.0
    #   means that the workspace or module cannot be used with Go 1.20 or
    #   with Go 1.21rc1.
    # If we execute `go run` against a Go 1.20 `go.mod` and we use a Go 1.21
    # compiler, the compiler will refuse to run and will require that the
    # `go.mod` is updated to Go 1.21.
    # Extra context:
    #   - https://github.com/golang/go/issues/63370
    #   - https://www.jvt.me/posts/2023/08/31/go-121-why-upgrade/
    # Hopefully, we can remove this small hack once we migrate all of our
    # code to Go 1.21 or add the `toolchain` directive in go.mod.
    local rancher_go_version=""
    if grep -Eq "^go 1.20" go.mod; then
        rancher_go_version="go1.20"
    fi

    HOME=$(pwd) REPO=rancher TAG=dev GOTOOLCHAIN="$rancher_go_version" go run pkg/image/export/main.go \
        system-charts \
        charts \
        rancher/rancher:"${image}" \
        rancher/rancher-agent:"${image}" \
        "${WINS_AGENT_UPGRADE_IMAGE}" \
        "${SYSTEM_AGENT_UPGRADE_IMAGE}" \
        "${SYSTEM_AGENT_INSTALLER_RKE2_IMAGES[@]}" \
        "${SYSTEM_AGENT_INSTALLER_K3S_IMAGES[@]}"
}

download_images_artifact() {
    local version="$1"

    if (curl --fail -LO "https://github.com/rancher/rancher/releases/download/${version}/rancher-images-sources.txt"); then
        # First we try to download the artifact from the public release in GH.
        # no-op
        :
    elif (curl --fail -LO "https://prime.ribs.rancher.io/rancher/${version}/rancher-images-sources.txt"); then
        # Otherwise we check if it's available in the Prime repo.
        # no-op
        :
    else
        echo "=> Unable to find image artifact file for Rancher's $version version"
        exit 1
    fi
}

add_version_tag() {
    local version="$1"

    # Add 'release/vX.Y' as a tag at the end of each line, so we can identify to which release the image belongs to.
    # This is needed, because now we are doing multi-release scan, so one image can belong to multiple releases.
    sed -i'' "s/$/,release\/rancher\/$version/" rancher-images-sources.txt
    mv rancher-images-sources.txt ../rancher-images-sources-"$version".txt
    echo "=> Generated Rancher $version images:"
    cd .. && cat rancher-images-sources-"$version".txt
}

generate_harvester_images() {
    echo "=> Generating Harvester's standalone images"
    ./generate-images-harvester.sh
}

generate_longhorn_images() {
    echo "=> Generating Longhorn's standalone images"
    ./generate-images-longhorn.sh
}

generate_rke2_images() {
    echo "=> Generating RKE2's standalone images"
    ./generate-images-rke2.sh
}

cd $(dirname $0)

for i in "${RELEASES[@]}"; do
    if parse_release "${i}"; then
        echo "=> Generating Rancher ${RANCHER_IMAGE_VERSION} images"
        remove_rancher_dir

        if "${RELEASE}"; then
            mkdir rancher && cd rancher
            download_images_artifact "${RANCHER_RELEASE}"
        else
            generate_images "${RANCHER_RELEASE}" "${CHARTS_RELEASE}" "${RANCHER_IMAGE_VERSION}"
        fi

        add_version_tag "${RANCHER_IMAGE_VERSION}"
        ./remove-patch-versions.sh "rancher-images-sources-${RANCHER_IMAGE_VERSION}.txt"
    else
        echo "=> The passed release version '$i' is not valid"
    fi
done

generate_harvester_images
generate_longhorn_images
generate_rke2_images

# Generate a temporary file with only the unique name:version of the images.
awk -F" " '{ print $1 }' rancher-images-sources-* "$HARVESTER_IMAGES" "$LONGHORN_IMAGES" "$RKE2_IMAGES" | sort -u > unique-images.txt

rm -f images-sources.txt
for i in $(cat unique-images.txt); do
    # For each unique image:version, we extract all the tags from each scanned
    # release. Then, we:
    # 1. Split the tags, that are separated by a comma, into multiple lines.
    # 2. Sort them uniquely.
    # 3. Recombine them in one line and separate them again with a comma.
    # 4. Remove the trailing comma.
    sources=$(grep "$i " rancher-images-sources-* "$HARVESTER_IMAGES" "$LONGHORN_IMAGES" "$RKE2_IMAGES" | \
        awk -F" " '{print $2}' | \
        tr ',' '\n'            | \
        sort -u                | \
        tr '\n' ','            | \
        sed "s/,$//")
    echo $i $sources | sed 's/,$//' >> images-sources.txt
done

# Clean up leftover files.
rm -rf rancher
rm rancher-images-sources-* unique-images.txt

# We keep these files for them to be uploaded to the repo.
mv images-sources.txt "$HARVESTER_IMAGES" "$LONGHORN_IMAGES" "$RKE2_IMAGES" .. && cd ..

echo "=> Generated Rancher unique image sources to scan"
cat images-sources.txt

