#!/usr/bin/env bash
# Thu 22 Sep 2016 13:05:54 CEST

# Build utilities

# Determines the os name we're using
osname() {
  [[ "$(uname -s)" == "Darwin" ]] && echo "macosx" || echo "linux"
}


# Functions for coloring echo commands
log_debug() {
  echo -e "(`date +%T`) \033[1;32m${@}\033[0m"
}


log_info() {
  echo -e "(`date +%T`) \033[1;34m${@}\033[0m"
}


log_warn() {
  echo -e "(`date +%T`) \033[1;35mWarning: ${@}\033[0m" >&2
}


log_error() {
  echo -e "(`date +%T`) \033[1;31mError: ${@}\033[0m" >&2
}


# Checks a given environment variable is set (non-zero size)
check_env() {
  if [ -z "${1+abc}" ]; then
    log_error "Variable ${1} is undefined - aborting...";
    exit 1
  else
    log_info "${1}=${!1}";
  fi
}


# Exports a given environment variable, verbosely
export_env() {
  if [ -z "${1+abc}" ]; then
    log_error "Variable ${1} is undefined - aborting...";
    exit 1
  else
    export ${1}
    log_info "export ${1}=${!1}";
  fi
}


# Checks a given environment variable is set (non-zero size)
check_pass() {
  if [ -z "${1+abc}" ]; then
    log_error "Variable ${1} is undefined - aborting...";
    exit 1
  else
    log_info "${1}=********";
  fi
}


# Function for running command and echoing results
run_cmd() {
  log_info "$ ${@}"
  ${@}
  local status=$?
  if [ ${status} != 0 ]; then
    log_error "Command Failed \"${@}\""
    exit ${status}
  fi
}


# Prepares ~/.pypirc
lock_pypirc() {
  local lockfile=/var/tmp/pypirc_lock
  local rc=${HOME}/.pypirc
  local maxtries=10
  local try=0
  local sleeptime=30 #seconds

  while true; do
    if [[ ${try} -lt ${maxtries} ]]; then
      ((try++))
      if ( set -o noclobber; echo "$$" > "${lockfile}") 2> /dev/null; then
        log_info "Successfully acquired ${lockfile}"
        echo $$ > ${lockfile}
        log_info "trapping on ${lockfile}..."
        trap 'rm -f "${lockfile}"; exit $?' INT TERM EXIT

        # start: protected code
        log_info "Creating ${rc}..."
        if [ -e ${rc} ]; then
          run_cmd rm -f ${rc}
        fi
        cat <<EOT >> ${rc}
[distutils]
index-servers =
    production
    staging

[production]
repository: ${PYPISERVER}
username: ${PYPIUSER}
password: ${PYPIPASS}

[staging]
repository: ${TESTSERVER}
username: ${PYPIUSER}
password: ${PYPIPASS}
EOT
        run_cmd chmod 600 ${rc}
        # end: protected code
        break
      else
        log_warn "${lockfile} exists, owned by process $(cat $lockfile)"
        log_info "Will retry after a ${sleeptime} seconds sleep (${try}/${maxtries})"
        run_cmd sleep ${sleeptime}
      fi
    else
      log_error "I already retried deploying ${try} times. Aborting..."
      log_error "You can retry this step when less packages are building."
      exit 1
    fi
  done
}


# Cleans ~/.pypirc, if the lock file belongs to us
unlock_pypirc() {
  local lockfile=/var/tmp/pypirc_lock
  local rc=${HOME}/.pypirc

  # untrap if lock belongs to the running process
  if [[ $(cat ${lockfile}) == $$ ]]; then
    run_cmd rm -r ${lockfile}
    run_cmd rm -rf ${rc}
    log_info "$ trap - INT TERM EXIT"
    trap - INT TERM EXIT
  fi
}


# Runs setup.py in a deployment context. If fails, tries to unlock
# the ${HOME}/.pypirc file lock
setup_deploy() {
  log_info "$ ${@}"
  ${PREFIX}/bin/python setup.py ${@}
  local status=$?
  if [ ${status} != 0 ]; then
    log_error "Command Failed \"${@}\""
    unlock_pypirc #just tries
    exit ${status}
  fi
}


# Uploads a file to our intranet location via curl
doc_upload() {
  log_info "curl: ${1} -> ${DOCSERVER}/${2}..."
  curl --location --silent --show-error --user "${DOCUSER}:${DOCPASS}" --upload-file ${1} ${DOCSERVER}/${2}
  local status=$?
  if [ ${status} != 0 ]; then
    log_error "Curl command finished with an error condition (status=${status})"
    exit ${status}
  fi
  log_info "Successfully uploaded ${1} with curl"
}


# Activates environment and sets up compilation
# $1: root of the conda installation
# $2: your current build prefix
prepare_build_env() {
  # Activates conda environment for the build
  log_info "$ source $1/bin/activate $2"
  source $1/bin/activate $2

  # Configures CCACHE
  # use_ccache=`which ccache`
  # if [ -z "${use_ccache}" ]; then
  #   log_warn "Cannot find ccache, compiling from scratch..."
  # else
  #   local ccache_bin=$2/lib/ccache
  #   if [ ! -d ${ccache_bin} ]; then
  #     run_cmd mkdir -pv ${ccache_bin}
  #     ln -sf ${use_ccache} ${ccache_bin}/gcc
  #     ln -sf ${use_ccache} ${ccache_bin}/g++
  #     ln -sf ${use_ccache} ${ccache_bin}/cc
  #     ln -sf ${use_ccache} ${ccache_bin}/c++
  #   fi
  #   use_gcc=`which gcc`
  #   PATH=${ccache_bin}:${PATH}
  #   export_env PATH
  #   log_info "ccache installed at ${use_ccache}, caching compilations..."
  #   log_info "gcc installed at ${use_gcc}..."
  # fi
}


# Appends a value to a variable if that is not already set
# $1: variable name to append the value
# $2: the value to be appended
append_if_not_set() {
  if [ -z "${1+abc}" ]; then
    eval $1="$2"
  elif [[ "${!1}" != "*${2}*" ]]; then
    eval $1="${!1} $2"
  fi
}


# Checks if an array contains a value
# taken from here: https://stackoverflow.com/questions/3685970/check-if-an-array-contains-a-value
# Parameters: <value-to-check> <array-variable>
# Usage: "a string" "${array[@]}"
contains_element () {
  local e
  for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
  return 1
}


check_env PYTHON_VERSION
check_env CI_PROJECT_DIR
check_env CI_PROJECT_PATH
check_env CI_PROJECT_NAME
check_env CI_BUILD_REF
check_env CI_BUILD_REF_NAME
check_pass PYPIUSER
check_pass PYPIPASS
check_pass DOCUSER
check_pass DOCPASS

# Sets up variables
OSNAME=`osname`

if [ -z "${CONDA_FOLDER}" ]; then
  CONDA_FOLDER=/opt/conda
fi

PYVER=py$(echo ${PYTHON_VERSION} | tr -d '.')
if [ -z "${CONDA_ENV}" ]; then
  if [ -d "${CONDA_FOLDER}/envs/bob-devel-${PYVER}-${CI_BUILD_REF_NAME}" ]; then
    CONDA_ENV=bob-devel-${PYVER}-${CI_BUILD_REF_NAME}
  else
    CONDA_ENV=bob-devel-${PYVER}
  fi
fi
BOB_PREFIX_PATH=${CONDA_FOLDER}/envs/${CONDA_ENV}

if [ -z "${DOCSERVER}" ]; then
  DOCSERVER=http://www.idiap.ch
  export_env DOCSERVER
fi

if [ -z "{PREFIX}" ]; then
  PREFIX=${CI_PROJECT_DIR}/build-prefix
  # In case we're setting-up the prefix, erase it if it exists
  if [ -d "${PREFIX}" ]; then
    run_cmd rm -rf ${PREFIX}
  fi
fi

if [ "${OSNAME}" == "linux" ]; then
  # Temporary hack to get building done right with gcc-5 compilers
  if [ -z "${CFLAGS}" ]; then
    CFLAGS="-D_GLIBCXX_USE_CXX11_ABI=0 -pthread"
  else
    CFLAGS="${CFLAGS} -D_GLIBCXX_USE_CXX11_ABI=0 -pthread"
  fi
else
  CFLAGS=""
fi
CXXFLAGS=${CFLAGS}

if [ -z "${PYPISERVER}" ]; then
  PYPISERVER="https://pypi.python.org/pypi"
fi

TESTSERVER=https://testpypi.python.org/pypi

check_env OSNAME
check_env PYVER
check_env PREFIX
export_env PREFIX
export_env CFLAGS
export_env CXXFLAGS
export_env BOB_PREFIX_PATH
check_env DOCSERVER
check_env PYPISERVER
check_env TESTSERVER
check_env CONDA_FOLDER
check_env CONDA_ENV

if [ -z "${CI_BUILD_TAG}" ]; then
  DEFSRV="${DOCSERVER}/software/bob/docs/latest/bob/%s/master/"
  if [ -z "${BOB_DOCUMENTATION_SERVER}" ]; then
    BOB_DOCUMENTATION_SERVER="${DEFSRV}"
  else
    BOB_DOCUMENTATION_SERVER="${BOB_DOCUMENTATION_SERVER}|${DEFSRV}"
  fi
  unset DEFSRV
  export_env BOB_DOCUMENTATION_SERVER
else
  log_info "Building tag, not setting BOB_DOCUMENTATION_SERVER"
fi