#!/usr/bin/env bash
set -eo pipefail
[[ $TRACE ]] && set -x

readonly ROOT_DIR="$(cd "$(dirname "$(dirname "${BASH_SOURCE[0]}")")" && pwd)"
readonly TMP_WORK_DIR="$(mktemp -d "/tmp/dokku-release.XXXXXX")"
readonly DOKKU_GIT_REV="$(git rev-parse HEAD)"

trap 'rm -rf "$TMP_WORK_DIR" >/dev/null' RETURN INT TERM EXIT

log-info() {
  # shellcheck disable=SC2034
  declare desc="Log info formatter"
  echo "$*"
}

log-error() {
  # shellcheck disable=SC2034
  declare desc="Log error formatter"
  echo "!   $*" 1>&2
}

log-fail() {
  # shellcheck disable=SC2034
  declare desc="Log fail formatter"
  log-error "$*"
  exit 1
}

fn-build-dokku() {
  declare desc="Builds dokku packages within a docker container"

  pushd "$ROOT_DIR" >/dev/null
  docker build \
    -f "contrib/build-dokku-update.Dockerfile" \
    -t dokku-update:build .
  return "$?"
}

fn-extract-package() {
  declare desc="Extract packages from a docker container to the root directory"
  declare PACKAGE_NAME="$1"

  if [[ -z "$PACKAGE_NAME" ]]; then
    log-error "Invalid deb file specified"
    return 1
  fi

  log-info "(extract-package) writing ${PACKAGE_NAME} to correct path"
  docker run --rm --entrypoint cat dokku-update:build "/tmp/${PACKAGE_NAME}" >"${ROOT_DIR}/build/${PACKAGE_NAME}"
  return "$?"
}

fn-publish-package() {
  declare desc="Publishes a package to packagecloud"
  declare IS_RELEASE="$1" RELEASE_TYPE="$2" PACKAGE_NAME="$3"
  local REPOSITORY=dokku/dokku-betafish DIST=ubuntu
  local OS_ID ex EXIT_CODE=0

  [[ "$IS_RELEASE" == "true" ]] && REPOSITORY=dokku/dokku
  [[ "$RELEASE_TYPE" == "rpm" ]] && DIST=el/7

  if [[ "$DIST" == "ubuntu" ]]; then
    OS_IDS=("xenial" "bionic" "focal")
    for OS_ID in "${OS_IDS[@]}"; do
      log-info "(release-dokku-update) pushing ${RELEASE_TYPE} to packagecloud.com/${REPOSITORY}/${DIST}"
      package_cloud push "${REPOSITORY}/${DIST}/${OS_ID}" "$PACKAGE_NAME"
      ex="$?"
      if [[ "$ex" -ne "0" ]]; then
        EXIT_CODE="$ex"
      fi
    done

    DIST=debian
    OS_IDS=("stretch" "buster")
    for OS_ID in "${OS_IDS[@]}"; do
      log-info "(release-dokku-update) pushing ${RELEASE_TYPE} to packagecloud.com/${REPOSITORY}/${DIST}"
      package_cloud push "${REPOSITORY}/${DIST}/${OS_ID}" "$PACKAGE_NAME"
      ex="$?"
      if [[ "$ex" -ne "0" ]]; then
        EXIT_CODE="$ex"
      fi
    done
  else
    log-info "(release-dokku-update) pushing ${RELEASE_TYPE} to packagecloud.com/${REPOSITORY}/${DIST}"
    package_cloud push "${REPOSITORY}/${DIST}" "$PACKAGE_NAME"
    EXIT_CODE="$?"
  fi
  return "$EXIT_CODE"
}

fn-in-array() {
  declare desc="return true if value ($1) is in list (all other arguments)"

  local e
  for e in "${@:2}"; do
    [[ "$e" == "$1" ]] && return 0
  done
  return 1
}

fn-is-release() {
  declare desc="Checks if a given run is a release run"
  declare RELEASE="$1"
  local IS_RELEASE=false
  if [[ "$RELEASE" == "major" ]] || [[ "$RELEASE" == "minor" ]] || [[ "$RELEASE" == "patch" ]]; then
    IS_RELEASE=true
  fi

  echo "$IS_RELEASE"
}

fn-require-bin() {
  declare desc="Checks that a binary exists"
  declare BINARY="$1"
  if ! command -v "$BINARY" &>/dev/null; then
    log-fail "Missing ${BINARY}, please install it"
  fi
}

main() {
  declare RELEASE="$1"
  local NEXT_VERSION
  local VALID_RELEASE_LEVELS=("major" "minor" "patch" "betafish" "build")

  if [[ "$RELEASE" == '--trace' ]]; then
    shift 1
    RELEASE="$1"
    TRACE=1 && set -x
  fi

  if [[ -z "$RELEASE" ]]; then
    log-fail "Argument 1 must be one of [major, minor, patch, betafish, build], none given"
  fi

  if ! fn-in-array "$RELEASE" "${VALID_RELEASE_LEVELS[@]}"; then
    log-fail "Argument 1 must be one of [major, minor, patch, betafish, build], '${RELEASE}' given"
  fi

  mkdir -p "build"
  fn-require-bin "docker"
  if [[ "$RELEASE" != "build" ]]; then
    fn-require-bin "package_cloud"
    [[ -n "$PACKAGECLOUD_TOKEN" ]] || log-fail "Missing PACKAGECLOUD_TOKEN environment variable"
  fi

  NEXT_VERSION="$(grep DOKKU_UPDATE_VERSION deb.mk | head -n1 | cut -d'=' -f2 | xargs)"
  IS_RELEASE="$(fn-is-release "$RELEASE")"

  fn-build-dokku || log-fail "Error building package"
  fn-extract-package "dokku-update_${NEXT_VERSION}_amd64.deb" || log-fail "Error extracting deb package"
  fn-extract-package "dokku-update-${NEXT_VERSION}-1.x86_64.rpm" || log-fail "Error extracting rpm package"

  if [[ "$RELEASE" != "build" ]]; then
    fn-publish-package "$IS_RELEASE" "deb" "build/dokku-update_${NEXT_VERSION}_amd64.deb" || log-fail "Error publishing deb package"
    fn-publish-package "$IS_RELEASE" "rpm" "build/dokku-update-${NEXT_VERSION}-1.x86_64.rpm" || log-fail "Error publishing rpm package"
  fi
}

main "$@"
