#!/bin/sh
# $FreeBSD: ports/Tools/portbuild/scripts/pdispatch,v 1.40 2011/01/26 10:41:53 linimon Exp $

#
# pdispatch <arch> <branch> <buildid> <host> <command> <package.tbz> [<args> ...]
#
# server-side script to dispatch the job to a host via the ptimeout script.

pb=/var/portbuild

arch=$1
branch=$2
buildid=$3
host=$4
command=$5
shift 5

pbab=${pb}/${arch}/${branch}

. ${pb}/conf/server.conf
. ${pb}/conf/common.conf
. ${pb}/${arch}/portbuild.conf
. ${pb}/scripts/buildenv

timeout=${PDISPATCH_TIMEOUT}
loglength=${PDISPATCH_LOGLENGTH}
hdrlength=${PDISPATCH_HDRLENGTH}

buildid=$(resolve ${pb} ${arch} ${branch} ${buildid})
if [ -z "${buildid}" ]; then
    echo "Invalid build ID ${buildid}"
    exit 1
fi

builddir=${pbab}/builds/${buildid}
buildenv ${pb} ${arch} ${branch} ${builddir}

# XXX needed still?
unset DISPLAY

# Allow override by HPN-SSH for performance
if [ -z "${ssh_cmd}" ]; then
    ssh_cmd=ssh
fi
if [ -z "${scp_cmd}" ]; then
    scp_cmd=scp
fi

pkgname=$(basename $1 ${PKGSUFFIX})

if [ -z "${pkgname}" ]; then
    echo "null packagename"
    exit 1
fi

args=${1+"$@"}
flags=""
clean=1
if [ "x$NOCLEAN" != "x" ]; then
    flags="${flags} -noclean"
    clean=0
fi
if [ "x$NO_RESTRICTED" != "x" ]; then
    flags="${flags} -norestr"
fi
if [ "x$NOPLISTCHECK" != "x" ]; then
    flags="${flags} -noplistcheck"
fi
if [ "x$NO_DISTFILES" = "x" ]; then
    flags="${flags} -distfiles"
fi
if [ "x$FETCH_ORIGINAL" != "x" ]; then
    flags="${flags} -fetch-original"
fi
if [ "x$TRYBROKEN" != "x" ]; then
    flags="${flags} -trybroken"
fi

chroot=
. ${pb}/${arch}/portbuild.conf
test -f ${pb}/${arch}/portbuild.${host} && . ${pb}/${arch}/portbuild.${host}
chrootdata=$(${ssh_cmd} -a -n ${client_user}@${host} ${sudo_cmd} ${pb}/scripts/claim-chroot ${arch} ${branch} ${buildid} ${pkgname} 2>&1)
if [ -z "${chrootdata}" ]; then
    echo "Failed to claim chroot on ${host}"
    exit 254
fi

case "${chrootdata}" in
    */var/portbuild/scripts/claim-chroot*)
	# Error executing script, assume system is booting
	chrootdata="wait boot"
	;;
esac

#    echo "Got ${chrootdata} from ${host}"

set -- ${chrootdata}
if [ $# -ge 2 ]; then
    case $1 in
	chroot)
	    chroot=$2
	    ;;
	setup)
	    echo "Setting up ${arch}/${branch} build ID ${buildid} on ${host}"

	    # Run in the background so we can potentially
	    # claim a slot on another machine.  In
	    # practise I think we often end up trying
	    # again on the same machine though.
		    
	    # Make sure to close stdin/stderr in the child
	    # or make will hang until the child process
	    # exits
	    ${pb}/scripts/dosetupnode ${arch} ${branch} ${buildid} ${host} > /tmp/setupnode.$$ 2>&1 &
	    exit 253
	    ;;
	error)
	    echo "Error reported by ${host}: $2"
	    ;;
	wait)
	    echo "Waiting for setup of ${host} to finish"
	    ;;
    esac
    shift 2
fi
	
if [ -z "${chroot}" ]; then
    exit 254
fi

. ${pb}/${arch}/portbuild.conf
test -f ${pb}/${arch}/portbuild.${host} && . ${pb}/${arch}/portbuild.${host}
    
rm -f ${builddir}/logs/${pkgname}.log ${builddir}/logs/${pkgname}.log.bz2
rm -f ${builddir}/errors/${pkgname}.log ${builddir}/errors/${pkgname}.log.bz2
    
${pb}/scripts/ptimeout.host $timeout ${ssh_cmd} -a -n ${client_user}@${host} ${sudo_cmd} ${command} ${arch} ${branch} ${buildid} ${chroot} ${flags} \"$ED\" \"$PD\" \"$FD\" \"$BD\" \"$RD\" ${args} 2>&1
error=$?

# Pull in the results of the build from the client
    
${scp_cmd} ${client_user}@${host}:${chroot}/tmp/${pkgname}.log ${builddir}/logs/${pkgname}.log
(${ssh_cmd} -a -n ${client_user}@${host} test -f ${chroot}/tmp/work.tbz ) && ${scp_cmd} ${client_user}@${host}:${chroot}/tmp/work.tbz ${builddir}/wrkdirs/${pkgname}.tbz
    
# XXX Set dirty flag if any of the scp's fail
    
mkdir -p ${builddir}/distfiles/.pbtmp/${pkgname}
${ssh_cmd} -a -n ${client_user}@${host} tar -C ${chroot}/tmp/distfiles --exclude ${chroot}/tmp/distfiles/RESTRICTED -cf - . | \
    tar --unlink -C ${builddir}/distfiles/.pbtmp/${pkgname} -xvf - && \
    touch ${builddir}/distfiles/.pbtmp/${pkgname}/.done
    
if [ "${error}" = 0 ]; then
    ${ssh_cmd} -a -n ${client_user}@${host} tar -C ${chroot}/tmp -cf - packages | \
	tar --unlink -C ${builddir} -xvf -

    # XXX why is this needed? 
    test -f ${builddir}/packages/All/${pkgname}${PKGSUFFIX} && \
	touch ${builddir}/packages/All/${pkgname}${PKGSUFFIX}

    if [ -f ${builddir}/errors/${pkgname}.log ]; then
	rm -f ${builddir}/errors/${pkgname}.log
	# Force rebuild of html page to remove this package from list
	touch ${builddir}/errors/.force
    fi
    lockf -k ${pbab}/failure.lock ${pb}/scripts/buildsuccess ${arch} ${branch} ${buildid} ${pkgname}
    log=${builddir}/logs/$pkgname.log
    if grep -q "even though it is marked BROKEN" ${log}; then
	echo | mail -s "${pkgname} BROKEN but built on ${arch} ${branch}" ${mailto}
    fi
    if grep -q "^list of .*file" ${log}; then
	buildlogdir=$(realpath ${builddir}/logs/)
	baselogdir=$(basename ${buildlogdir})
	(sed -e '/^build started/,$d' $log;echo;echo "For the full build log, see"; echo; echo "  http://${MASTER_URL}/errorlogs/${arch}-errorlogs/${baselogdir}/$(basename $log)";echo;sed -e '1,/^=== Checking filesystem state/d' $log) | mail -s "${pkgname} pkg-plist errors on ${arch} ${branch}" ${mailto}
    fi
else
    log=${builddir}/errors/${pkgname}.log
    ${scp_cmd} ${client_user}@${host}:${chroot}/tmp/${pkgname}.log ${log}
    result=$?
    if [ $result -ne 0 ]; then
	(echo ${chroot}@${host}; ${ssh_cmd} -a -n ${client_user}@${host} ls -laR ${chroot}/tmp) | mail -s "${pkgname} logfile not found" ${mailto}
    else
	if ! grep -q "even though it is marked BROKEN" ${log}; then
	    buildlogdir=$(realpath ${builddir}/logs/)
	    baselogdir=$(basename ${buildlogdir})
	    if [ $(wc -l ${log} | awk '{print $1}') -le $((loglength + hdrlength)) ]; then
		(echo "You can also find this build log at"; echo; echo "  http://${MASTER_URL}/errorlogs/${arch}-errorlogs/${baselogdir}/$(basename $log)";echo;cat ${log}) | mail -s "${pkgname} failed on ${arch} ${branch}" ${mailto}
	    else
		(echo "Excerpt from the build log at"; echo; echo "  http://${MASTER_URL}/errorlogs/${arch}-errorlogs/${baselogdir}/$(basename $log)";echo;sed -e '/^build started/,$d' $log;echo;echo "  [... lines trimmed ...]";echo;tail -${loglength} ${log}) | mail -s "${pkgname} failed on ${arch} ${branch}" ${mailto}
	    fi
	fi
	lockf -k ${pbab}/failure.lock ${pb}/scripts/buildfailure ${arch} ${branch} ${buildid} ${pkgname}
    fi
fi

${ssh_cmd} -a -n ${client_user}@${host} ${sudo_cmd} ${pb}/scripts/clean-chroot ${arch} ${branch} ${buildid} ${chroot} ${clean}

  # XXX Set a dirty variable earlier and check here
if grep -q "^build of .*ended at" ${builddir}/logs/${pkgname}.log; then
    exit ${error}
else
    echo "Build of ${pkgname} in ${host}:/${chroot} failed uncleanly"
    exit 255
fi
