#!/usr/bin/env bash

## This script builds the Rancher server image exclusively, sans Dapper

set -eo pipefail
set -x

# variables
COMMIT=$(git rev-parse --short HEAD)
TAG="${TAG:-$(grep -m1 ' TAG:' .github/workflows/pull-request.yml | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' -e "s/\${{ github.sha }}/$COMMIT/g" | cut -d' ' -f2)}"
OS="${OS:-linux}"
ARCH="${ARCH:-amd64}"
REPO="${REPO:-rancher}"
BINARY_DEBUG=${BINARY_DEBUG:-false}
CATTLE_K3S_VERSION=$(grep -m1 'ENV CATTLE_K3S_VERSION=' package/Dockerfile | cut -d '=' -f2)
CATTLE_KDM_BRANCH=$(grep -m1 'ARG CATTLE_KDM_BRANCH=' package/Dockerfile | cut -d '=' -f2)
CATTLE_RANCHER_WEBHOOK_VERSION=$(grep -m1 'webhookVersion' build.yaml | cut -d ' ' -f2)
CATTLE_REMOTEDIALER_PROXY_VERSION=$(grep -m1 'remoteDialerProxyVersion' build.yaml | cut -d ' ' -f2)
CATTLE_CSP_ADAPTER_MIN_VERSION=$(grep -m1 'cspAdapterMinVersion' build.yaml | cut -d ' ' -f2)
CATTLE_RANCHER_PROVISIONING_CAPI_VERSION=$(grep -m1 'provisioningCAPIVersion' build.yaml | cut -d ' ' -f2)
CATTLE_RANCHER_TURTLES_VERSION=$(grep -m1 'turtlesVersion' build.yaml | cut -d ' ' -f2)
CATTLE_FLEET_VERSION=$(grep -m1 'fleetVersion' build.yaml | cut -d ' ' -f2)
CATTLE_HELM_VERSION=$(grep -m1 'ENV CATTLE_HELM_VERSION=' package/Dockerfile | cut -d '=' -f2)

# download kontainer driver metadata
curl -sLf https://releases.rancher.com/kontainer-driver-metadata/"${CATTLE_KDM_BRANCH}"/data.json >./data.json

BUILD_ARGS=()
BUILD_ARGS+=("--build-arg=VERSION=${TAG}")
BUILD_ARGS+=("--build-arg=ARCH=${ARCH}")
BUILD_ARGS+=("--build-arg=IMAGE_REPO=${REPO}")
BUILD_ARGS+=("--build-arg=COMMIT=${COMMIT}")
BUILD_ARGS+=("--build-arg=RKE_VERSION=${RKE_VERSION}")
BUILD_ARGS+=("--build-arg=CATTLE_RANCHER_WEBHOOK_VERSION=${CATTLE_RANCHER_WEBHOOK_VERSION}")
BUILD_ARGS+=("--build-arg=CATTLE_REMOTEDIALER_PROXY_VERSION=${CATTLE_REMOTEDIALER_PROXY_VERSION}")
BUILD_ARGS+=("--build-arg=CATTLE_RANCHER_PROVISIONING_CAPI_VERSION=${CATTLE_RANCHER_PROVISIONING_CAPI_VERSION}")
BUILD_ARGS+=("--build-arg=CATTLE_RANCHER_TURTLES_VERSION=${CATTLE_RANCHER_TURTLES_VERSION}")
BUILD_ARGS+=("--build-arg=CATTLE_CSP_ADAPTER_MIN_VERSION=${CATTLE_CSP_ADAPTER_MIN_VERSION}")
BUILD_ARGS+=("--build-arg=CATTLE_FLEET_VERSION=${CATTLE_FLEET_VERSION}")
BUILD_ARGS+=("--build-arg=CATTLE_HELM_VERSION=${CATTLE_HELM_VERSION}")
BUILD_ARGS+=("--build-arg=RANCHER_TAG=${TAG}")
BUILD_ARGS+=("--build-arg=RANCHER_REPO=${REPO}")
if [ "$BINARY_DEBUG" = true ]; then
  # Remove -s (strip symbols)
  BUILD_ARGS+=("--build-arg=LINKFLAGS=-extldflags -static")
  # Disable compiler optimizations
  BUILD_ARGS+=("--build-arg=GCFLAGS=all=-N -l")
fi

# because macos doesn't have realpath apparently
abs_path() {
  echo "$(cd "$(dirname "$1")" && pwd -P)/$(basename "$1")"
}

is_safe_local_directive() {
  while IFS= read -r safe_path; do
    safe_path="$(abs_path "$safe_path")"
    if [[ "$1" == "$safe_path"* ]]; then
      return 0
    fi
  done < <(echo "$BUILD_SAFE_DIRS" | tr ':' '\n')
  return 1
}

needs_workdir="false"

# add_context adds _some_ support for local replace directives of dependency.
add_context() {
  if ! replace=$(grep "$1 =>" go.mod); then
    return 0
  fi

  # Detect local replace directive or either form:
  #             github.com/rancher/steve => /absolute/or/relative/path/to/steve
  # or
  #     replace github.com/rancher/steve => /absolute/or/relative/path/to/steve
  if [ -n "$(echo "$replace" | cut -d= -f2 | cut -d' ' -f3)" ]; then
    return 0
  fi

  set +x
  godep=$(echo "$replace" | cut -d= -f2 | cut -d' ' -f2)
  path=$(abs_path "$godep")
  if ! is_safe_local_directive "$path"; then
    cat <<EOF
Detected replace directive with path $godep ($path). This directive is not listed under a safe
prefix path with BUILD_SAFE_DIRS environment variable.

Path you want to use with replace directive must be under a prefix path set in the BUILD_SAFE_DIRS
env var. Its value should be a colon-separated (:) list of prefix paths.
For example, for a path of /home/user/sources/steve, you could set BUILD_SAFE_DIRS=/home/user/sources.
EOF
    exit 1
  fi

  set -x
  BUILD_ARGS+=("--build-context=$2=$path")
  BUILD_ARGS+=("--build-arg=$3=$2")
  BUILD_ARGS+=("--build-arg=$3_PATH=$path")
  needs_workdir="true"
}

add_context "github.com/rancher/apiserver" "apiserver-context" "GODEP_APISERVER"
add_context "github.com/rancher/lasso" "lasso-context" "GODEP_LASSO"
add_context "github.com/rancher/norman" "norman-context" "GODEP_NORMAN"
add_context "github.com/rancher/remotedialer" "remotedialer-context" "GODEP_REMOTEDIALER"
add_context "github.com/rancher/shepherd" "shepherd-context" "GODEP_SHEPHERD"
add_context "github.com/rancher/steve" "steve-context" "GODEP_STEVE"
add_context "github.com/rancher/wrangler/v3" "wrangler-context" "GODEP_WRANGLER"

if [ "$needs_workdir" = "true" ]; then
  BUILD_ARGS+=("--build-arg=BUILD_WORKDIR=$PWD")
fi

if [ "$TARGET" = "k3s-images" ]; then
  docker buildx build \
    "${BUILD_ARGS[@]}" \
    --output=type=local,dest=$PWD/bin \
    --platform="${OS}/${ARCH}" \
    --target k3s-images \
    --file ./package/Dockerfile .
fi

if [ "$TARGET" = "binary-server" ]; then
  docker buildx build \
    "${BUILD_ARGS[@]}" \
    --output=type=local,dest=$PWD \
    --platform="${OS}/${ARCH}" \
    --target server-binary \
    --file ./package/Dockerfile .
fi

if [ -z "$TARGET" ] || [ "$TARGET" = "server" ]; then
  # start the builds
  docker buildx build \
    "${BUILD_ARGS[@]}" \
    --tag "${REPO}"/rancher:"${TAG}" \
    --platform="${OS}/${ARCH}" \
    --target server \
    --file ./package/Dockerfile .

  if [ "$PUSH" = "true" ]; then
    docker push "${REPO}"/rancher:"${TAG}" &
  fi
fi

if [ -z "$TARGET" ] || [ "$TARGET" = "agent" ]; then
  docker buildx build \
    "${BUILD_ARGS[@]}" \
    --tag "${REPO}"/rancher-agent:"${TAG}" \
    --platform="${OS}/${ARCH}" \
    --target agent \
    --file ./package/Dockerfile .

  if [ "$PUSH" = "true" ]; then
    docker push "${REPO}"/rancher-agent:"${TAG}" &
  fi
fi

wait
