#!/bin/bash

# Copyright UiPath 2021
#
# =================
# LICENSE AGREEMENT
# -----------------
#   Use of paid UiPath products and services is subject to the licensing agreement
#   executed between you and UiPath. Unless otherwise indicated by UiPath, use of free
#   UiPath products is subject to the associated licensing agreement available here:
#   https://www.uipath.com/legal/trust-and-security/legal-terms (or successor website).
#   You must not use this file separately from the product it is a part of or is associated with.

set -e

SOURCE_REGISTRY_URL=${SOURCE_REGISTRY_URL:-"registry.uipath.com"}
TARGET_REGISTRY_URL=${TARGET_REGISTRY_URL:-""}
IMAGES_MANIFEST=${IMAGES_MANIFEST:-""}
HELM_CHARTS_MANIFEST=${HELM_CHARTS_MANIFEST:-""}
REGISTRY_CLIENT="docker"


function display_usage() {
  echo
  echo "***************************************************************************************"
  echo
  echo "mirror-registry.sh copies the offline installation artifacts for Automation Suite to another OCI compliant registry."
  echo
  echo "Usage:"
  echo "  $0 [flags]"
  echo
  echo "Parameters:"
  echo "  --target-registry-url                             Target OCI compliant registry for the artifacts."
  echo "  --images-manifest                                 Path to a manifest file containing the list of the images."
  echo "  --helm-charts-manifest                            Path to a manifest file containing the list of the helm charts."
  echo "  --source-registry-url                             Target OCI compliant registry for the artifacts. Default UiPath public registry."
  echo
  echo "Flags:"
  echo "  -h|--help                                         Display help"
  echo "  -d|--debug                                        Run in debug mode"
  echo
  echo "***************************************************************************************"
  echo
}

function parse_long_args() {
  while (("$#")); do
    case "$1" in
    -d | --debug)
      echo "Running in debug"
      set -x
      shift
    ;;

    -h | --help)
      display_usage
      shift
      exit 0
    ;;

    --target-registry-url)
      if [ -n "$2" ] && [ "${2:0:1}" != "-" ]; then
        TARGET_REGISTRY_URL=$2
      else
        echo "Value for $1 is missing"
        exit 1
      fi
      shift 2
    ;;

    --source-registry-url)
      if [ -n "$2" ] && [ "${2:0:1}" != "-" ]; then
      SOURCE_REGISTRY_URL=$2
      else
        echo "Value for $1 is missing"
        exit 1
      fi
      shift 2
    ;;

    --images-manifest)
      if [ -n "$2" ] && [ "${2:0:1}" != "-" ]; then
      IMAGES_MANIFEST=$2
      else
        echo "Value for $1 is missing"
        exit 1
      fi
      shift 2
    ;;

    --helm-charts-manifest)
      if [ -n "$2" ] && [ "${2:0:1}" != "-" ]; then
      HELM_CHARTS_MANIFEST=$2
      else
        echo "Value for $1 is missing"
        exit 1
      fi
      shift 2
    ;;

    -*|*) # unsupported flags
      display_usage
      echo "echo: Unsupported command or flag $1"
      exit 1
    ;;
    esac
  done
  if [ -z "${TARGET_REGISTRY_URL}" ]; then
    echo "Target registry mandatory parameter missing."
    exit 1
  fi
  if [ -z "${IMAGES_MANIFEST}" ] && [ -z "${HELM_CHARTS_MANIFEST}" ]; then
    echo "At least one manifest is mandatory."
    exit 1
  fi
}

function copy_images() {
  local images=("$@")
  
  for image in "${images[@]}"; do
    [ -z "${image}" ] && continue
    local pulled_image pushed_image
    local try
    local maxtry=3
    local status

    pulled_image="${SOURCE_REGISTRY_URL}/${image}"
    pushed_image="${TARGET_REGISTRY_URL}/${image}"
  
    try=0
    status="notready"
     while [[ ${status} == "notready" ]] && ((try != maxtry)); do
      try=$((try + 1))
      echo "[${try}/${maxtry}] Pulling ${pulled_image}..."
      ${REGISTRY_CLIENT} pull "${pulled_image}" > /dev/null && status="ready"
    done
    [[ ${status} == "ready" ]] || (echo "Failed to pull image ${pulled_image}" && exit 1)
    echo "[Done] Pulling ${pulled_image}"

    ${REGISTRY_CLIENT} tag "${pulled_image}" "${pushed_image}" > /dev/null

    try=0
    status="notready"
    while [[ ${status} == "notready" ]] && ((try != maxtry)); do
      try=$((try + 1))
      echo "[${try}/${maxtry}] Pushing ${pushed_image}"
      ${REGISTRY_CLIENT} push "${pushed_image}" > /dev/null && status="ready"
    done
    [[ ${status} == "ready" ]] || (echo "Failed to push image ${pushed_image}" && exit 1)
    echo "[Done] Pushing ${pulled_image}"
  done
}

function copy_helm_charts() {
  local helm_charts=("$@")
  local try
  local maxtry=3
  local status
  
  for chart in "${helm_charts[@]}"; do
    local namespace chart_name chart_version chart_ref
    [ -z "${chart}" ] && continue
    # Expecting chart in format <namespace>/<chart_name>:<version>
    chart_ref=${chart%:*}
    chart_version=${chart#*:}
    namespace=${chart_ref%/*}
    chart_name=${chart_ref#*/}

    try=0
    status="notready"
    while [[ ${status} == "notready" ]] && ((try != maxtry)); do
      try=$((try + 1))
      echo "[${try}/${maxtry}] Pulling ${chart}..."
      helm pull "oci://${SOURCE_REGISTRY_URL}/${namespace}/${chart_name}" --version "${chart_version}" --untar -d . > /dev/null && status="ready" && break
      rm -rf "${chart_name}"
    done
    [[ ${status} == "ready" ]] || (echo "Failed to pull helm chart ${chart}" && exit 1)
    echo "[Done] Pulling ${chart}"

    helm package "${chart_name}" --version "${chart_version}" -d . > /dev/null

    try=0
    status="notready"
    while [[ ${status} == "notready" ]] && ((try != maxtry)); do
      try=$((try + 1))
      echo "[${try}/${maxtry}] Pushing ${chart}"
      helm push "${chart_name}-${chart_version}.tgz" "oci://${TARGET_REGISTRY_URL}/${namespace}" > /dev/null  && status="ready" && break
    done
    rm -f "${chart_name}-${chart_version}.tgz"
    [[ ${status} == "ready" ]] || (echo "Failed to push helm chart ${chart}" && exit 1)
    echo "[Done] Pushing ${chart}"

    rm -rf "${chart_name}"
  done
}

function main() {
  local helm_charts images
  if [ -n "${IMAGES_MANIFEST}" ]; then
    readarray -t images < "${IMAGES_MANIFEST}"
    copy_images "${images[@]}"
  fi

  if [ -n "${HELM_CHARTS_MANIFEST}" ]; then
    readarray -t helm_charts < "${HELM_CHARTS_MANIFEST}"
    copy_helm_charts "${helm_charts[@]}"
  fi
}

parse_long_args "$@"
main
