#!/bin/bash

##############################################################################
# lrauv-application nightly build script.
#
# This is the main script to perform a full build of the lrauv-application.
# No arguments expected; any specific steps and ordering to be indicated
# within the script itself.
#
# See https://bitbucket.org/mbari/lrauv-application/issues/18
#     https://mbari1.atlassian.net/browse/TETHYS-563
#
# === NOTE ===
# - Per the cronjob described below, a copy of this script should be found
#   under /home/tethysadmin/nightly-build/bin/.
# - Also, if such directory contains a `slackInfo.json` file, then no regular standard
#   output is generated by this script, which would otherwise trigger the traditional
#   cronjob report delivered via email. Instead, a Slack notification is generated via
#   the webhook URL indicated in `slackInfo.json`, expected to be like this:
#     {
#        "webhook": "https://hooks.slack.com/services/...."
#     }
#   The notification in this case is a short message to the associated channel with a
#   link to the full build report.
#
# This script starts by performing a full clone of lrauv-application.
# The cloned directory will be located under:
#     /var/www/html/lrauv/nightly_builds/YYYY-MM-DD/
# where YYYY-MM-DD corresponds to current date.
#
# This YYYY-MM-DD/ directory will contain:
#    lrauv-application/           # the clone and full build (*)
#    do_nightly_build.stdout      # full generated stdout
#
# (*) Only the most recent week of such clones are kept (but all reports are retained).
#
# tethysadmin's crontab entry:
#
#   29 01 * * * nice -18 /home/tethysadmin/nightly-build/bin/do_nightly_build.sh
#
##############################################################################

set -e  # any error should stop the build
set -u  # make sure any referenced variable is set

# captured as given when logging in as tethysadmin@tethyshub:
export PATH=/home/tethysadmin/.local/bin:/home/tethysadmin/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/opt/tethysl/bin

NIGHTLY_BUILDS_DIR=/var/www/html/lrauv/nightly_builds
BASEDIR=`date --iso`
STDOUT=${NIGHTLY_BUILDS_DIR}/${BASEDIR}/do_nightly_build.stdout

WEB_NIGHTLY_BUILDS_DIR="http://tethyshub.shore.mbari.org/lrauv/nightly_builds"
WEB_STDOUT=${WEB_NIGHTLY_BUILDS_DIR}/${BASEDIR}/do_nightly_build.stdout

# Destination for generated module JSONs:
: ${JSON_DEST_DIR:=${NIGHTLY_BUILDS_DIR}/${BASEDIR}/json}

# define XSD_DEST_DIR with desired default or from the environment if provided
: ${XSD_DEST_DIR:=/mbari/LRAUV/xsd}

PUBLISH_SCHEMA_DIR=/var/www/html/tethys/Xml/

slackInfoJson=/home/tethysadmin/nightly-build/bin/slackInfo.json
slackUrl=""

function main {
    checkSlack
    prepare
    SECONDS=0

    show "========================================================"
    log "Nightly build starting"
    show "========================================================"

    do_clone
    do_self_check
    do_make_lcmtypes
    do_make
    do_publish_lrauv_info
    do_module_jsons
    do_schema
    do_nav_charts
    do_sim_daemon
    do_unit_tests
    do_regression_tests
    do_docs
    #do_style BR 11/06/2020 disabling until fixed 

    duration=$SECONDS
    show "\n========================================================"
    log "Nightly build complete ($(($duration / 60))mins:$(($duration % 60))secs)"
    show "========================================================"

    exit_script
}

# Sets slackUrl if its value can be extracted from $slackInfoJson
function checkSlack {
    if [ -f "${slackInfoJson}" ]; then
        slackUrl=$(jq -r .webhook ${slackInfoJson})
    fi
}

function prepare {
    mkdir -p ${NIGHTLY_BUILDS_DIR}
    cd       ${NIGHTLY_BUILDS_DIR}

    # keep at most a week of nightly builds (but all reports are retained).
    # So, remove clone and build of 7 days ago:
    rm -rf `date --iso -d '-7 days'`/lrauv-application

    backup=""
    if [ -d "${BASEDIR}" ]; then
        backup="${BASEDIR}_`stat -c %Y ${BASEDIR}`"
        mv ${BASEDIR} ${backup}
    fi

    mkdir ${BASEDIR}
    cd    ${BASEDIR}
    > ${STDOUT}

    if [ "${backup}" != "" ]; then
        log "Pre-existing ${BASEDIR} moved to ${backup}"
    fi
    show "\n"
    log "PWD: `pwd`"
    log "PATH: ${PATH}\n"
}

# Performs a full clone under ${NIGHTLY_BUILDS_DIR}/${BASEDIR}/lrauv-application
function do_clone {
    log_header "Cloning..."
    log "Using `git --version` (located at `which git`)\n"
    CMD="git clone git@bitbucket.org:mbari/lrauv-application.git --recursive --depth=1"
    show "${CMD}"
    # Note: occasionally Bitbucket times out while running the clone command:
    #   ssh_exchange_identification: read: Connection timed out
    # The following checks for any error on the 1st attempt, retrying a second time:
    set +e
    runCmd "${CMD}"
    clone_result=$?
    set -e
    if [ "${clone_result}" != "0" ]; then
        rm -rf lrauv-application
        show ""
        log "clone command failed! Will retry in a few minutes."
        sleep 5m
        log "Retrying clone command..."
        runCmd "${CMD}"
    fi
    show ""
    log "Repository cloned.\n"
    cd lrauv-application
    show "PWD: `pwd`\n"
    show "Last commit: git log -1"
    runCmd git log -1
}

# compares this script with cloned script to verify same contents
function do_self_check {
    CLONED_SCRIPT="${NIGHTLY_BUILDS_DIR}/${BASEDIR}/lrauv-application/Build/do_nightly_build.sh"
    THIS_SCRIPT="$(cd -P -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)/do_nightly_build.sh"
    CMD="diff ${CLONED_SCRIPT} ${THIS_SCRIPT}"
    set +e
    ${CMD} > /dev/null 2>&1
    if [ "$?" != "0" ]; then
        show "\nWARNING: ${THIS_SCRIPT} differs from latest version!\n"
    fi
    set -e
}

function do_make_lcmtypes {
    log_header "Building lcmtypes: (cd lrauv-lcmtypes && make)"
    cd lrauv-lcmtypes
    runCmd make
    cd ..
    show ""
    log "lcmtypes build complete"
}

function do_make {
    CMD="make XSD_DEST_DIR=${XSD_DEST_DIR}"
    log_header "Building: ${CMD}"
    runCmd "${CMD}"
    show ""
    log "Build complete (make)"
}

function do_publish_lrauv_info {
    CMD="make tl-publish-lrauv-info"
    log_header "Running: ${CMD}"
    runCmd "${CMD}"
    show ""
    log "tl-publish-lrauv-info complete"
}

function do_module_jsons {
    PYTHONPATH="Source/json:${PYTHONPATH:-}"
    export PYTHONPATH
    CMD="Source/json/AllModulesToJson.py . ${JSON_DEST_DIR}"
    log_header "Generating module JSONs: ${CMD}"
    runCmd "${CMD}"
    show ""
    log "Module JSON generation complete"
}

function do_schema {
    CMD="make XSD_DEST_DIR=${XSD_DEST_DIR} -C Build/ schema"
    log_header "Generating schemas: ${CMD}"
    runCmd "${CMD}"
    show ""
    log "Schema generation complete"
    CMD="cp -p ${XSD_DEST_DIR}/* ${PUBLISH_SCHEMA_DIR}"
    log_header "Publishing schemas: ${CMD}"
    runCmd "${CMD}"
    show ""
    log "Schemas ready to be published"
}

function do_nav_charts {
    mkdir -p ./Data
    CMD="bin/process_nav Config/regressionTests/Navigation.cfg"
    log_header "Preparing nav charts: ${CMD}"
    runCmd "${CMD}"
    log "Navigation charts prepared\n"
}

function do_sim_daemon {
    killall -q SimDaemon || true  # -q for quiet but still code is 1 if no process was killed
    CMD="bin/SimDaemon"
    log_header "Restarting SimDaemon: ${CMD}"
    runCmd "${CMD}"
    log "SimDaemon restarted\n"
}

function do_unit_tests {
    CMD="bin/LRAUVTest"
    log_header "Unit testing: ${CMD}"
    runCmd "${CMD}"
    log "Unit testing complete\n"
}

function do_regression_tests {
    CMD="python2 Tools/regression/runTest.py"
    log_header "Regression testing: ${CMD}"
    runCmd "${CMD}"
    show ""
    log "Regression testing complete"
}

function do_docs {
    CMD="make XSD_DEST_DIR=${XSD_DEST_DIR} -C Build/ doxygen"
    log_header "Building documentation: ${CMD}"
    runCmd "${CMD}"
    log "Documentation build complete"

    CMD="cp -rf Documentation/html/* /var/www/html/lrauv/doc/"
    log "Publishing documentation: ${CMD}"
    runCmd "${CMD}"
    log "Documentation published: http://tethyshub.shore.mbari.org/lrauv/doc/"
}

function do_style {
    CMD="make XSD_DEST_DIR=${XSD_DEST_DIR} -C Build/ cxxcheck"
    log_header "Checking style: ${CMD}"
    runCmd "${CMD}"
    show ""
    log "Style check complete"
}

function log_header {
    show  "\n----------------------------"
    log "$1"
    show "----------------------------\n"
}

function log {
    echo -e "[$(date --rfc-3339=seconds)]: $1" >> "${STDOUT}" 2>&1
}

function show {
    echo -e "$1" >> "${STDOUT}" 2>&1
}

# Helper to run a command with all output to ${STDOUT}
function runCmd {
    CMD="$*"
    ${CMD} >> "${STDOUT}" 2>&1
}

# Pushes notification to Slack
function slack_push {
    text=$1
    set +e
    # https://api.slack.com/messaging/webhooks#posting_with_webhooks
    # https://httpie.io/docs#scripting
    http --check-status --ignore-stdin --timeout=2.5 POST "${slackUrl}" text="$text" >/dev/null 2>&1
    res=$?
    set -e
    if [ "${res}" != "0" ]; then
        # In this case, let's just trigger the regular email notification with some output:
        echo "WARN: Notification via Slack seems to have failed (HTTPie returned ${res})"
        echo "$text"
    fi
}

# Do the slack notification if so configured, or print the link to the report to stdout
function exit_script {
    text="*lrauv-application* build completed - Report at ${WEB_STDOUT}"
    if [[ "$slackUrl" != "" ]]; then
        slack_push "$text"
    else
        echo "$text"
    fi
}

main
