#!/bin/sh

fail() {
  echo "${@}" >&2
  exit 1
}

on_tag() {
  if [ -n "$CURRENT_TAG" ]; then
    echo "${@}"
    eval "${@}"
    return $?
  else
    return 0
  fi
}

fail_on_error() {
  "${@}"

  exit=$?
  if [ "$exit" -ne "0" ]; then
    fail "${@} exited with $exit"
  fi

  return 0
}

verify_environment() {
  if [ -z "$TRAVIS_OS_NAME" ]; then
    fail "\$TRAVIS_OS_NAME is not set or empty."
  fi
}

verify_linux_environment() {
  if [ -z "$ARCH" ]; then
    fail "\$ARCH is not set or empty."
  fi

  if [ -z "$ARCH_CMD" ]; then
    fail "\$ARCH_CMD is not set or empty."
  fi
}

on_os() {
  os="$1"
  shift

  verify_environment

  if [ "$TRAVIS_OS_NAME" = "$os" ]; then
    echo "${@}"
    eval "${@}"
    return $?
  else
    return 0
  fi
}

on_linux() {
  fail_on_error on_os "linux" "${@}"
}

on_osx() {
  fail_on_error on_os "osx" "${@}"
}

prepare_system() {
  on_linux 'echo '"'"'{"ipv6":true, "fixed-cidr-v6":"2001:db8:1::/64"}'"'"' | sudo tee /etc/docker/daemon.json'
  on_linux sudo service docker restart

  on_osx brew update
}

build() {
  with_build_env 'make std_spec clean'
  with_build_env 'make crystal std_spec compiler_spec docs'
  with_build_env 'find samples -name "*.cr" | xargs -L 1 ./bin/crystal build --no-codegen'
  with_build_env './bin/crystal tool format --check samples spec src'
}

prepare_build() {
  on_linux verify_linux_environment

  on_osx brew install crystal-lang

  # Make sure binaries from llvm are available in PATH
  on_osx brew install jq
  on_osx OSX_LLVM_PACKAGE=`brew info --json=v1 crystal-lang | jq '.[].dependencies | .[] | select(startswith("llvm"))'`
  on_osx brew link --force $OSX_LLVM_PACKAGE
}

with_build_env() {
  command="$1"

  # Ensure non GMT timezone
  export TZ="America/New_York"

  on_linux verify_linux_environment

  export DOCKER_TEST_PREFIX="crystallang/crystal:0.25.0"

  case $ARCH in
    x86_64)
      export DOCKER_TEST_IMAGE="$DOCKER_TEST_PREFIX-build"
      ;;
    i386)
      export DOCKER_TEST_IMAGE="$DOCKER_TEST_PREFIX-i386-build"
      ;;
  esac

  on_linux docker run \
    --rm -t \
    -u $(id -u) \
    -v $PWD:/mnt \
    -w /mnt \
    -e CRYSTAL_CACHE_DIR="/tmp/crystal" \
    "$DOCKER_TEST_IMAGE" \
    "$ARCH_CMD" /bin/sh -c "'$command'"

  on_osx sudo systemsetup -settimezone $TZ
  on_osx PATH="/usr/local/opt/llvm/bin:\$PATH" \
    CRYSTAL_CACHE_DIR="/tmp/crystal" \
    /bin/sh -c "'$command'"

}

usage() {
  cat <<EOF
bin/ci [-h|--help] command [parameter ...]

Helper script to prepare and run the testsuite on Travis CI.

Commands:
  prepare_system          setup any necessaries repositories etc.
  prepare_build           download and extract any dependencies needed for the build
  build                   run specs, build crystal, run format check, build samples, build the docs
  with_build_env command  run command in the build environment
  help                    display this

EOF
}

command="$1"
shift
case $command in
  prepare_system)
    prepare_system
    ;;
  prepare_build)
    prepare_build
    ;;
  with_build_env)
    target_command="${@}"
    with_build_env "$target_command"
    ;;
  build)
    build
    ;;
  -h|--help|help)
    usage
    ;;
  *)
    if [ -n "$command" ]; then
      fail "Unknown command $command"
    else
      usage
      exit 1
    fi
    ;;
esac
