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

# Build utilities

# Determines the operating system 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
# $1: Path to the file to upload (e.g. dist/myfile.whl)
# $2: Path on the server to upload to (e.g. wheels-upload/gitlab/)
doc_upload() {
  log_info "curl: ${1} -> ${DOCSERVER}/${2}..."
  local code=`curl --location --silent --fail --write-out "%{http_code}" --user "${DOCUSER}:${DOCPASS}" --upload-file ${1} ${DOCSERVER}/${2}`
  if [[ ${code} == 204 || ${code} == 201 ]]; then
    log_info "Successfully uploaded ${1} with curl"
  else
    log_error "Curl command finished with an error condition (code=${code}):"
    curl --location --silent --user "${DOCUSER}:${DOCPASS}" --upload-file ${1} ${DOCSERVER}/${2}
    exit ${status}
  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

if [ -z "${VIRTUALENV_PATH}" ]; then
  VIRTUALENV_PATH=env
fi

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

PREFIX=${CI_PROJECT_DIR}/${VIRTUALENV_PATH}

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"
  else
      if [[ "${CFLAGS}" != *-D_GLIBCXX_USE_CXX11_ABI=0* ]]; then
        CFLAGS="${CFLAGS} -D_GLIBCXX_USE_CXX11_ABI=0"
      fi
  fi
else #macosx
  if [ "${CFLAGS}" == *-DBZ_DEBUG* ]; then
    # -DBZ_DEBUG does not work well with clang
    CFLAGS=`echo ${CFLAGS} | sed -e s/\s*-DBZ_DEBUG//g`
  fi
fi
CXXFLAGS=${CFLAGS}

PYVER=py$(echo ${PYTHON_VERSION} | tr -d '.')
if [ -z "${BOB_PREFIX_PATH}" ]; then
  # Default on stock installations for our CIs
  BOB_PREFIX_PATH=${CONDA_FOLDER}/envs/bob-devel-${PYVER}

  # Unless, a special environment (to be tested) exists matching the branch
  if [ -d ${BOB_PREFIX_PATH}-${CI_BUILD_REF_NAME} ]; then
    BOB_PREFIX_PATH=${BOB_PREFIX_PATH}-${CI_BUILD_REF_NAME}
  fi
fi
LD_LIBRARY_PATH=${BOB_PREFIX_PATH}/lib
if [ "${OSNAME}" == "macosx" ]; then
  DYLD_FALLBACK_LIBRARY_PATH=${BOB_PREFIX_PATH}/lib
  MACOSX_DEPLOYMENT_TARGET=10.9
fi

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 CFLAGS
export_env CXXFLAGS
check_env DOCSERVER
check_env PYPISERVER
check_env TESTSERVER
check_env CONDA_FOLDER
check_env VIRTUALENV_PATH
export_env LD_LIBRARY_PATH
if [ "${OSNAME}" == "macosx" ]; then
  export_env DYLD_FALLBACK_LIBRARY_PATH
  export_env MACOSX_DEPLOYMENT_TARGET
fi
export_env BOB_PREFIX_PATH

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

# Activates conda environment
run_cmd source ${BOB_PREFIX_PATH}/bin/activate `basename ${BOB_PREFIX_PATH}`