#!/bin/bash -e

# The following variables are available to you
# (values are examples only)
# 
# TIMEZONE="UTC"                                        # The timezone this server should be given
# CI_USER="ci"                                          # The user to setup and run the tests as 
#                                                       # (although you are free to ignore this)
# 
# GIT_URI="git://github.com/andymccurdy/redis-py.git"   # The Git URL for this project
# GIT_PK_FILE="git.pk"                                  # The Git PK file location
# GIT_BRANCH="master"                                   # The Git branch to use
# BUILD_ID="123"                                        # The continuous build ID
# BUILD_SECRET="aaabbbcccdddeeefff111222333"            # The continuous build secret
# BUNDLE_ROOT_URL="https://continuous.io                # The root URL to perform callbacks to
# 
# 
# Very few things here are actually required, and those that are are clearly 
# marked. Root access is available via the 'sudo' command.
# 
# You can customise variables within this script by setting up a .continuousrc file:
# 
# https://continuous.io/docs/customising/



# The directory where the bootstrap has downloaded files to
# (including where this script is located)
SCRIPT_DIR="/tmp/cisetup"

# A sensible default location in which to look for any pip requirements
PIP_REQUIREMENTS="requirements.pip"



### SYSTEM SETUP ###

# Load the default values in
. ~/.bash_profile

# Simple authentication for remote logger, 
echo "$BUILD_ID:$BUILD_SECRET:"

# Now we have printed logger info, start with the verbose output
set -x

# Let continuous know that we configuring the instance now
curl -d "status=configuring&secret=$BUILD_SECRET" "$BUNDLE_ROOT_URL/buildservices/build/$BUILD_ID/update-status/"

echo "[INFO] The server is being configured (`lsb_release -sd` `lsb_release -sc` `uname -m`)"

# Check we are running as the expected user
if [ $USER != $CI_USER ]; then
    echo "[ERROR] Script must be run as the user defined by CI_USER ($CI_USER)" >&2
    exit 1
fi

# Set the timezone
if [ "$TIMEZONE" ]; then
    if [ ! -e "/usr/share/zoneinfo/$TIMEZONE" ]; then
        echo "[WARNING] Timezone '$TIMEZONE' could not be found. Timezone will not be set."  >&2
    else
        sudo su -c "echo $TIMEZONE > /etc/timezone"
        sudo dpkg-reconfigure --frontend noninteractive tzdata 
    fi
fi

# Update apt
sudo apt-get -y -q update

# Accept ssh fingerprints
sudo su -c 'echo "    StrictHostKeyChecking no" >> /etc/ssh/ssh_config'

# Install some packages
sudo apt-get -y -q install git-core build-essential python-dev curl

# Setup the services
for serviceScript in `ls $SCRIPT_DIR/service-*`; do
    echo "Running service script $serviceScript"
    sudo chmod +x $serviceScript
    sudo $serviceScript
done

# Setup the user
mkdir -p ~/.ssh

### PYTHON SETUP ###

echo "[INFO] Your project is now being loaded from source control"

# Setup the SSH agent
echo "eval \`ssh-agent -s\` > /dev/null" >> ~/.bash_profile
. ~/.bash_profile

# Get source (git/svn/tar.gz?)

get_from_git() {
    local GIT_PATH="/tmp/git-$RANDOM"
    
    if [ "$GIT_PK_FILE" ]; then
        sudo cp $SCRIPT_DIR/$GIT_PK_FILE /home/$CI_USER/.ssh/id_rsa
        sudo chmod 600 /home/$CI_USER/.ssh/id_rsa
        sudo chown $CI_USER:$CI_USER /home/$CI_USER/.ssh/id_rsa
    fi
    
    git clone $GIT_URI $GIT_PATH
    mv $GIT_PATH/.git ~
    
    # get the files back
    git reset --hard HEAD;
    
    # get the branch we need
    (git branch | grep $GIT_BRANCH)  > /dev/null || git branch $GIT_BRANCH origin/$GIT_BRANCH
    
    # checkout the branch
    git checkout $GIT_BRANCH
    
    # pull any updates
    git pull
    
    # setup the submodules
    git submodule init
    git submodule update
    
    
}

get_from_git

echo "[INFO] The Python environment is now being configured"

# pip & virtualenv
sudo apt-get -y -q install python-setuptools python-pip
sudo pip install -q virtualenv distribute

# Keep the environment outside of the project as infinite
# recursion errors can arise in some cases
ENV_DIR="/var/env_test"

sudo mkdir $ENV_DIR
sudo chown $CI_USER:$CI_USER $ENV_DIR

virtualenv --no-site-packages $ENV_DIR
echo ". $ENV_DIR/bin/activate" >> ~/.bash_profile
echo "export PIP_REQUIRE_VIRTUALENV=true" >> ~/.bash_profile
echo "export PIP_RESPECT_VIRTUALENV=true" >> ~/.bash_profile

# setup the python path
echo "export PYTHONPATH=/home/$CI_USER/lib:\$PYTHONPATH" >> ~/.bash_profile

. ~/.bash_profile

### Load in the .continuousrc file (if present)
if [ -e ~/.continuousrc ]; then
    echo "[INFO] A .continuousrc file was found, loading it in"
    . ~/.continuousrc
else
    echo "[INFO] No .continuousrc file was found, so it will not be loaded (this is okay!)"
fi

# Install any extra packages that are required
if [ "$EXTRA_PACKAGES" ]; then
    sudo apt-get -y install $EXTRA_PACKAGES
fi

# Setup the requirements if a file was specified
if [ -e "$PIP_REQUIREMENTS" ]; then
    pip install -E $ENV_DIR -r $PIP_REQUIREMENTS
fi

# Run pip install if setup.py is present
if [ -e "/home/$CI_USER/setup.py" ]; then
    pip install -E $ENV_DIR "/home/$CI_USER"
fi

# Make sure unittest-continuous is installed
pip install -E $ENV_DIR -e "git+git://github.com/continuous/unittest-continuous.git#egg=unittest-continuous"

echo "[INFO] Trying to determine how best to run your tests"

# How are we going to run our tests?
if [ ! "$TEST_COMMAND" ]; then
    TEST_COMMAND=`find /home/$CI_USER . -maxdepth 3 \( -iregex '.*/tests/.*tests.py' -or -iregex '.*/run_?test.*' \) -and -type f | head -n1`
    if [[ "$TEST_COMMAND" && ! -x "$TEST_COMMAND" ]]; then
        chmod +x $TEST_COMMAND
        TEST_COMMAND="$TEST_COMMAND"
    fi
fi

# Let's see if we have a manage.py command (for Django projects)
if [[ ! "$MANAGE_COMMAND" && ! "$TEST_COMMAND" ]]; then
    if which "django-admin.py"; then
        MANAGE_COMMAND=`which django-admin.py`
    else
        MANAGE_COMMAND=`find /home/$CI_USER -maxdepth 3 -name "manage.py" | head -n1`
    fi
fi

# Let's see if setuptools has a chance of running these tests
if [[ ! "$MANAGE_COMMAND" && ! "$TEST_COMMAND" && -f setup.py && `grep "test_suite" setup.py` ]]; then
    chmod +x /home/$CI_USER/setup.py
    TEST_COMMAND="/home/$CI_USER/setup.py test"
    INSTALL_TO="/home/$CI_USER/setup.py"
fi

if [[ ! "$MANAGE_COMMAND" && ! "$TEST_COMMAND" ]]; then
    echo "[ERROR] Could not auto-determine a value for MANAGE_COMMAND or TEST_COMMAND. Consider setting it manually in your .continuousrc file."
    exit 2
fi

if [ ! "$TEST_COMMAND" ]; then
    echo "[INFO] A Django command was found at '$MANAGE_COMMAND'. Assuming this is a Django project."
    
    # If we can see this file and it is not executable
    if [[ -f "$MANAGE_COMMAND" && ! -x "$MANAGE_COMMAND" ]]; then
        # ... then make it executable
        chmod +x $MANAGE_COMMAND
    fi
    
    TEST_COMMAND="$MANAGE_COMMAND test"
fi

echo "[INFO] Running your test with the command: $TEST_COMMAND"

### Now run the tests

# Find a place to install our setup code
if [ ! "$INSTALL_TO" ]; then
    i=0
    INSTALL_TO=""
    while [[ ! $INSTALL_TO && i -lt 5 ]]; do
        INSTALL_TO=`find /home/$CI_USER -maxdepth $i -name "__init__.py" | head -1`
        let i=$i+1
    done
fi

install_setup_code() {
    code="import unittest_continuous; unittest_continuous.setup()"
    if [ -s "$INSTALL_TO" ]; then
        tmpfile="/tmp/$RANDOM"
        awk -v text="$code" '!/^#/ && !p {print text; p=1} 1' $INSTALL_TO > $tmpfile
        mv $tmpfile $INSTALL_TO
    else
        echo "$code" > $INSTALL_TO
    fi
    
}

echo "[INFO] Installing the Continuous testing code to $INSTALL_TO"

# Install the setup code
install_setup_code

# Now get a list of apps to test (if we are using Django's manage command)
if [ "$MANAGE_COMMAND" ]; then
    MANAGE_COMMAND_DIR=`dirname $MANAGE_COMMAND`
    if [ ! "$APPS" ]; then
        i=0
        APPS=""
        while [[ ! $APPS && i -lt 5 ]]; do
            APPS=`find $MANAGE_COMMAND_DIR -maxdepth $i -name "models.py" | rev | cut -d/ -f2 | rev | tr "\\n" " "`
            let i=$i+1
        done
    fi
    
    echo "[INFO] As this is a Django project, we will tests these apps: $APPS"
fi

# Let continuous know that we are going to run the tests now
curl -d "status=running&secret=$BUILD_SECRET" "$BUNDLE_ROOT_URL/buildservices/build/$BUILD_ID/update-status/" > /dev/null

# Run the tests!
export BUILD_ID=$BUILD_ID
export BUILD_SECRET=$BUILD_SECRET
if [ "$DJANGO_SETTINGS_MODULE" ]; then
	SETTINGS="--settings $DJANGO_SETTINGS_MODULE"
fi

if [ ! "$DISABLE_COVERAGE" ]; then
    pip install --upgrade -E $ENV_DIR coverage
    if [ ! "$COVERAGE_COMMAND" ]; then
        COVERAGE_COMMAND='coverage run --omit "*/env_*" --'
    fi
fi

RUN="$COVERAGE_COMMAND $TEST_COMMAND $SETTINGS $APPS"

echo "[INFO] Tests are now being run with the command: $RUN"

eval "$RUN" | tee /tmp/testresults.log

echo "[INFO] Tests have been run"

# send the XML results to continuous
if [ -s "/home/$CI_USER/results.xml" ]; then
    echo "[INFO] Results found in /home/$CI_USER/results.xml. Send the data to Continuous now."
    
    # Use '--data-binary' to ensure unix new lines don't get ignored
    curl --data-binary @/home/$CI_USER/results.xml $BUNDLE_ROOT_URL/buildservices/build/$BUILD_ID/xml/?secret=$BUILD_SECRET > /dev/null
else
    echo "[ERROR] No results found at /home/$CI_USER/results.xml. Nothing to send back to Continuous."
    exit 3
fi

# Dump the coverage XML results
if [ ! "$DISABLE_COVERAGE" ]; then
    coverage xml -o coverage.xml
fi

# Send the coverage results back to continuous
if [ -f "coverage.xml" ]; then
    echo "[INFO] Code coverage data found in /home/$CI_USER/coverage.xml. Send the data to Continuous now."
    
    # Use '--data-binary' to ensure unix new lines don't get ignored.
    # This call returns a list of files to send to continuous (for showing coverage results only)
    curl --data-binary @/home/$CI_USER/coverage.xml $BUNDLE_ROOT_URL/buildservices/build/$BUILD_ID/coverage/?secret=$BUILD_SECRET > /tmp/coveragefiles.txt
    
    # Send the source files for continuous
    if [ ! "$DISABLE_SENDING_SOURCE" ]; then
        cat /tmp/coveragefiles.txt | xargs tar -c > /tmp/coveragefiles.tar
        curl --data-binary @/tmp/coveragefiles.tar $BUNDLE_ROOT_URL/buildservices/build/$BUILD_ID/coverage-source/?secret=$BUILD_SECRET
    fi
else
    if [ ! "$DISABLE_COVERAGE" ]; then
        echo "[WARNING] No code coverage results found at /home/$CI_USER/coverage.xml. Code coverage reports will not be available."
    else
        echo "[INFO] Code coverage reporting has been disabled by 'DISABLE_COVERAGE'. Skipping."
    fi
fi

run_js_hint() {
    
    if [ ! "$JS_DIR" ]; then
        JS_DIR="media"
        if [ ! -f "$JS_DIR"]; then
            JS_DIR=`find . -maxdepth 2 -name "media" -type d | head -n 1`
        fi
    fi
    
    if [ ! "$JS_DIR" ]; then
        echo "[WARNING] Could not determine a value for JS_DIR. Consider setting it in your .continuousrc file."
        return 0
    fi
    
    if [ ! "$JSLINT_COMMAND" ]; then
        JSLINT_COMMAND="jshint"
    fi
    
    files=`find . -name "*.js" | grep -v "min.js" | grep -v "/vendor/" | grep -v "/.npm/" | grep -v "/env*"`
    
    if [ "$files" ]; then
        echo "[INFO] Found `echo \"$files\" | wc -w` JavaScript files in $JS_DIR"
    else
        echo "[WARNING] No JavaScript files found in $JS_DIR. Consider setting JS_DIR."
        return 0
    fi
    
    # Setup node-jshint and run it
    echo "[INFO] Installing nodejs, npm and jshint"
    sudo apt-get -y install python-software-properties
    sudo add-apt-repository ppa:chris-lea/node.js
    sudo apt-get update
    sudo apt-get install -y nodejs nodejs-dev

    curl http://npmjs.org/install.sh | sudo clean=no sh

    sudo npm install -g jshint
    
    files=`echo "$files" | xargs`
    $JSLINT_COMMAND $files --jslint-reporter > jslint.xml
    curl --data-binary @jslint.xml $BUNDLE_ROOT_URL/buildservices/build/$BUILD_ID/jslint/?secret=$BUILD_SECRET > /dev/null
}

if [ ! "$DISABLE_JSLINT" ]; then
    run_js_hint
else
    echo "[INFO] JSLint has been disabled by 'DISABLE_JSLINT'. Skipping."
fi

# Let continuous know that we are done
curl -d "status=done&secret=$BUILD_SECRET" "$BUNDLE_ROOT_URL/buildservices/build/$BUILD_ID/update-status/" > /dev/null

# A simple was of ensure that the setup script finished
touch /tmp/passed

echo "[INFO] Complete!"
