#!/bin/bash
set -e

function maybe_touch_sstate() {
    :
}


# Check whether /bin/sh is dash
if [ -z "`/bin/sh -c 'echo $BASH_VERSION'`" ]; then
    echo "ERROR: /bin/sh is not bash." 1>&2
    echo 1>&2
    echo "Various parts of the build system currently require that" 1>&2
    echo "/bin/sh be bash (e.g. brightsign-field-update and unit tests.)" 1>&2
    echo 1>&2
    if [ -x /usr/sbin/dpkg-reconfigure ]; then
        echo "Try: sudo dpkg-reconfigure dash" 1>&2
    elif [ -x /bin/bash ]; then
        echo "Try: sudo ln -sf bash /bin/sh" 1>&2
    else
        echo "Try installing bash" 1>&2
    fi
    echo 1>&2
    exit 1
fi

# Ensure that lsb_release is present. If not, we'll end up looking in
# the wrong place in the sstate cache.
if [ -z "`lsb_release -i -s 2>/dev/null`" ]; then
    echo "ERROR: lsb_release is not available." 1>&2
    echo 1>&2
    echo "Correct sstate-cache directory naming relies on lsb_release." 1>&2
    echo 1>&2
    echo "Try: sudo apt-get install lsb-release" 1>&2
    echo 1>&2
    exit 1
fi

# If there are any symlinks in our path we need to get rid of them to
# avoid confusing ccache later.
cd `realpath .`

export oeroot=`pwd`/..
export SHELL=/bin/bash

if [ "$(cat /proc/sys/vm/max_map_count)" -lt 120000 ]; then
    (
        echo "ERROR: max_map_count is smaller than the recommended value."
        echo
        echo "Try doing something like this:"
        echo "  sudo sh -c 'echo 120000 > /proc/sys/vm/max_map_count'"
        echo
        echo "and then do this to make it permanent:"
        echo "  sudo sh -c 'echo \"vm.max_map_count = 120000\" > /etc/sysctl.d/local.conf'"
        echo
        echo "See https://jira.brightsign.biz/browse/OS-2440 for more details."
        echo
    ) 1>&2
    exit 1
fi

# Bitbake sometimes spins in an infinite loop consuming 100% CPU after
# receiving SIGTERM. Let's make sure it can't do that for very long by
# limiting it to two hours of real CPU time.
ulimit -t 7200

GIT_SSH=`pwd`/batch-ssh
export GIT_SSH

case "${MACHINE}" in
    "")
        echo "MACHINE not set." 1>&2
        exit 1
        ;;
    roadster|dart|opel)
        echo MACHINE \"${MACHINE}\" does not exist. Use MACHINE=pantera 1>&2
        exit 1
        ;;
    ranchero)
        echo MACHINE \"${MACHINE}\" does not exist. Use MACHINE=impala 1>&2
        exit 1
        ;;
    qemumipsel)
        # We support this for building gdb/binutils for classify-crash
        ;;
    *)
        if ! grep -q "^${MACHINE}$" supported-machines; then
           echo "MACHINE \"${MACHINE}\" not supported." 1>&2
           exit 1
        fi
        ;;
esac

if [ -z "$OE_TERMINAL" ]; then
    if [ -n "$TMUX" ]; then
        # If we're already running tmux then just create a new pane
        # within it. (Use PREFIX+! to turn it into a full window.)
        OE_TERMINAL="tmux-running"
    elif [ -z "$DISPLAY" ]; then
        OE_TERMINAL="screen"
    elif [ "$TERM" = "screen" ]; then
        OE_TERMINAL="screen"
    else
        OE_TERMINAL="gnome"
    fi
    echo "Setting OE_TERMINAL to $OE_TERMINAL (`date +'%T'`)"
    export OE_TERMINAL
fi

if [ -z "$BS_DEBUG" ]; then
    BS_DEBUG=0
fi
export BS_DEBUG

if [ -z "$WK_DEBUG" ]; then
    WK_DEBUG=0
fi

# Make sure we set CCACHE_DIR otherwise someone ends up making a
# directory actually named "${CCACHE_DIR}"!
if [ -z "${CCACHE_DIR}" ]; then
    export CCACHE_DIR=$HOME/.ccache
fi

# Make sure full paths get rewritten to partial ones if they are
# inside our build tree
export CCACHE_BASEDIR=`realpath ${oeroot}`

case "$BS_DEBUG" in
    0) DEBUG_MAYBE= ;;
    1) DEBUG_MAYBE=-debug ;;
    *)
        echo BS_DEBUG not set correctly. 1>&2
        exit 1
        ;;
esac

# Take care to not override BS_VERSION_SUFFIX being set to the empty
# string.
if [ -z "${BS_VERSION_SUFFIX+set}" ]; then
    BS_VERSION_SUFFIX="_${LOGNAME}-$(basename $(realpath ${oeroot}))"
fi

case "$DEPLOY_FOR_TFTPBOOT" in
    0) BS_TFTP_PUBLISH_PATH= ;;
    ""|1)
        BS_TFTP_PUBLISH_PATH=/srv/tftp/${USER}/${MACHINE}/
        [ -n "$BS_NFSROOT_LINK" ] || export BS_NFSROOT_LINK=${HOME}/nfsroots/${MACHINE}
        ;;
    *)
        echo DEPLOY_FOR_TFTPBOOT not set correctly. 1>&2
        exit 1
        ;;
esac

if [ -z "${BSBB_NOTIFY}" ]; then
    if [ -n "${DISPLAY}" ]; then
        BSBB_NOTIFY=/usr/bin/notify-send
    else
        BSBB_NOTIFY=/bin/true
    fi
fi
[ -x "${BSBB_NOTIFY}" ] || BSBB_NOTIFY=/bin/true
[ -x "${BSBB_NOTIFY_BEGIN}" ] || BSBB_NOTIFY_BEGIN=/bin/true

export DISTRO=brightsign

export BS_TFTP_PUBLISH_PATH

# If we don't have a local.conf at all then oe-init-build-env will create one.
# We don't want that to happen because the default contents are unhelpful.  Make
# an empty file to pre-empt that behaviour.
if [ ! -f conf/local.conf ]; then
  echo "CONF_VERSION = \"\${LOCALCONF_VERSION}\"" > conf/local.conf
fi

if grep -q '^EXTRA_IMAGE_FEATURES = "debug-tweaks"' conf/local.conf; then
    echo "You appear to have an automatically generated conf/local.conf." 1>&2
    echo "This may cause problems with debugging. Perhaps you should" 1>&2
    echo "remove it?" 1>&2
    exit 1
fi


(
    echo "BOS_VERSION = \"8.5.70\""
    echo "BOS_HASH = \"${bos_hash}\""
    echo "BS_VERSION_SUFFIX = \"${BS_VERSION_SUFFIX}\""
) > conf/brightsign-version.conf.new

if ! cmp conf/brightsign-version.conf conf/brightsign-version.conf.new >/dev/null 2>&1; then
    mv conf/brightsign-version.conf.new conf/brightsign-version.conf
else
    rm conf/brightsign-version.conf.new
fi

. $oeroot/oe-core/oe-init-build-env . ../bitbake >/dev/null

# Defaults that can be overridden if necessary by the configuration
# file:
export CAM_GERRIT_USERNAME=$LOGNAME
MIN_BB_NUMBER_THREADS=4
MAX_BB_NUMBER_THREADS=1024
MIN_PARALLEL_MAKE_COUNT=6
MAX_PARALLEL_MAKE_COUNT=1024
HOST_CPU_COUNT=$(nproc)
PARALLEL_MAKE_COUNT=${HOST_CPU_COUNT}
export BB_NUMBER_THREADS=${HOST_CPU_COUNT}

# .bsbbconfig and/or $XDG_CONFIG_HOME/bsbb can set:
# - BB_NUMBER_THREADS (or MIN_BB_NUMBER_THREADS and/or MAX_BB_NUMBER_THREADS)
# - PARALLEL_MAKE_COUNT (or MIN_PARALLEL_MAKE_COUNT and/or MAX_PARALLEL_MAKE_COUNT)
# It can refer to ${HOST_CPU_COUNT} if it so wishes, but assigning the
# MIN/MAX variables instead is recommended.

if [ -e ${XDG_CONFIG_HOME:=${HOME}/.config}/bsbb ]; then
    echo "NOTE: Using user-specific bsbb configuration"
    . ${XDG_CONFIG_HOME}/bsbb
fi
if [ -e .bsbbconfig ]; then
    echo "NOTE: Using source-tree-specific bsbb configuration"
    . ./.bsbbconfig
fi

function minmax_var()
{
    var="$1"
    min_var="MIN_${var}"
    max_var="MAX_${var}"

    value="${!var}"
    min_value="${!min_var}"
    max_value="${!max_var}"
    if [ "${value}" -gt "${max_value}" ]; then
        echo "NOTE: Reducing ${var} from ${value} to ${max_value}"
        eval "${var}=${max_value}"
    fi
    if [ "${value}" -lt "${min_value}" ]; then
        echo "NOTE: Increasing ${var} from ${value} to ${min_value}"
        eval "${var}=${min_value}"
    fi
}

minmax_var BB_NUMBER_THREADS
minmax_var PARALLEL_MAKE_COUNT
export PARALLEL_MAKE=-j${PARALLEL_MAKE_COUNT}

# Environment variables that are allowed through from our environment
# to the bitbake environment.
BB_ENV_EXTRAWHITE="$BB_ENV_EXTRAWHITE oeroot CCACHE_DISABLE CCACHE_BASEDIR CCACHE_DIR CCACHE_LOGFILE"
BB_ENV_EXTRAWHITE="$BB_ENV_EXTRAWHITE GIT_SSH OE_TERMINAL MACHINE BB_NUMBER_THREADS"
BB_ENV_EXTRAWHITE="$BB_ENV_EXTRAWHITE PARALLEL_MAKE BS_DEBUG BS_LTTNG WK_DEBUG BS_NXCLIENT"
BB_ENV_EXTRAWHITE="$BB_ENV_EXTRAWHITE BS_NFSROOT_LINK BB_NO_NETWORK BS_X11_ROOT DISTRO"
export BBENV_EXTRAWHITE

# tell any interested party that we're about to start on the slow stuff
${BSBB_NOTIFY_BEGIN}

# Ensure that the cached sources in /private/oe-sources and cached
# builds in the sstate cache can be read by everyone in the fw-eng
# group. Only Jenkins is allowed to populate those directories though.
umask 022

# If we need to build ccache then do so in advance so we always use
# our version rather than any system version. Force ccache to be
# disabled when we build ccache itself so that build still works even
# if ccache is unavailable.
ccache="tmp-glibc/sysroots-components/`uname -m`/ccache-native/usr/bin/ccache"
if [ ! -x "${ccache}" ]; then
    echo Building ccache first...
    if CCACHE_DISABLE=1 MACHINE=malibu time bitbake ccache-native; then
        : # success
    else
        exit_status=$?
        ${BSBB_NOTIFY} --icon=weather-storm "Build failed (ccache-native) for ${MACHINE} in `pwd`"
        echo BITBAKE ccache-native FAILED ${exit_status} 1>&2
        maybe_touch_sstate "$@"
        exit ${exit_status}
    fi
fi

minimum_ccache_capacity_gb=24
ccache_capacity_gb=`${ccache} -s|grep '^max cache size'|sed -r -e's,^max cache size,,g' -e 's,M(B|bytes), / 1024,g' -e 's,G(B|bytes), / 1,g' -e 's,T(B|bytes), \* 1024 / 1,g'|bc`
if [ -z "${ccache_capacity_gb}" ]; then
    echo "ERROR: failed to determine ccache size" 1>&2
    exit 1
fi
if [ "${ccache_capacity_gb}" -lt "${minimum_ccache_capacity_gb}" ]; then
    if [ -n "${WORKSPACE}" ]; then
        # We're running under Jenkins. Let's just fix ccache
        # automatically to save failing the build
        echo "WARNING: maximum ccache size for ${CCACHE_DIR} is worryingly small: ${ccache_capacity_gb}GiB"
        echo "         fixing it to 30GiB"
        ${ccache} -M30G
    else
        (
            echo "ERROR: maximum ccache size for ${CCACHE_DIR} is worryingly small: ${ccache_capacity_gb}GiB"
            echo "       try running: ${ccache} -M30G"
            echo
        ) 1>&2
        exit 1
    fi
fi

if time bitbake "$@"; then
    maybe_touch_sstate "$@"
    if [ -n "${BS_TFTP_PUBLISH_PATH}" ]; then
        mkdir -p ${BS_TFTP_PUBLISH_PATH}
        DEPLOYDIR=tmp-glibc/deploy/images/${MACHINE}

        case "${MACHINE}" in
            tiger|pantera|impala|pagani|malibu)
                vmlinuz_mission=${DEPLOYDIR}/vmlinuz-mission.bin
                vmlinuz_nfs=${DEPLOYDIR}/nfskernel/vmlinuz-nfs.bin
                vmlinuz_rescue=${DEPLOYDIR}/rescuekernel/vmlinuz-rescue.bin
                bolt=${DEPLOYDIR}/bolt.bin
                firstimages=${DEPLOYDIR}/firstimages.bin

                [ ! -e ${vmlinuz_mission} ] || rsync -a ${vmlinuz_mission} ${BS_TFTP_PUBLISH_PATH}/vmlinuz-mission
                [ ! -e ${vmlinuz_nfs} ] || rsync -a ${vmlinuz_nfs} ${BS_TFTP_PUBLISH_PATH}/vmlinuz
                [ ! -e ${vmlinuz_rescue} ] || rsync -a ${vmlinuz_rescue} ${BS_TFTP_PUBLISH_PATH}/vmlinuz-rescue
                [ ! -e ${bolt} ] || rsync -a ${bolt} ${BS_TFTP_PUBLISH_PATH}/bolt.bin
                [ ! -e ${firstimages} ] || rsync -a ${firstimages} ${BS_TFTP_PUBLISH_PATH}/firstimages.bin
                ;;

            sebring)
                fitimage_mission=${DEPLOYDIR}/fitImage-brightsign-verify-image-${MACHINE}-mission.bin
                fitimage_nfs=${DEPLOYDIR}/nfskernel/fitImage-nfs.bin
                fitimage_rescue=${DEPLOYDIR}/rescuekernel/fitImage-brightsign-rescue-image-${MACHINE}${DEBUG_MAYBE}-${MACHINE}
                uboot=${DEPLOYDIR}/u-boot.imx

                [ ! -e ${fitimage_mission} ] || rsync -a ${fitimage_mission} ${BS_TFTP_PUBLISH_PATH}/fitImage-mission
                [ ! -e ${fitimage_nfs} ] || rsync -a ${fitimage_nfs} ${BS_TFTP_PUBLISH_PATH}/fitImage-nfs
                [ ! -e ${fitimage_rescue} ] || rsync -a --copy-links ${fitimage_rescue} ${BS_TFTP_PUBLISH_PATH}/fitImage-rescue
                [ ! -e ${uboot} ] || rsync -a --copy-links ${uboot} ${BS_TFTP_PUBLISH_PATH}/u-boot.imx
                [ ! -e ${uboot} ] || [ ! -d "${MACHINE}-nfsroot" ] || rsync -a --copy-links ${uboot} ${MACHINE}-nfsroot/u-boot.imx
                ;;
        esac

        if [ -x ./.build-success-hook ]; then
            ./.build-success-hook
        fi
    fi
    ${BSBB_NOTIFY} --icon=weather-clear "Build complete for ${MACHINE} in `pwd`"
else
    exit_status=$?
    maybe_touch_sstate "$@"
    ${BSBB_NOTIFY} --icon=weather-storm "Build failed for ${MACHINE} in `pwd`"
    echo BITBAKE FAILED ${exit_status} 1>&2
    exit ${exit_status}
fi
