#!/bin/sh -
#
#   Copyright (c) 2010 Oliver Fromme, Germany <olli@fromme.com>
#   All rights reserved.  BSD license and disclaimer apply.
#   Please see /usr/share/examples/etc/bsd-style-copyright on
#   FreeBSD systems, or ask the author for a copy of the license.
#
#   This script helps testing specific parts of /usr/src for
#   all supported architectures, so you don't have to run a
#   full "make universe" which would take ages, especially on
#   slower hardware.
#
#   First you have to build the toolchain with the following
#   command.  This will take a while; it has to be done only
#   once, and after any significant changes to the toolchain.
#
#       # cd /usr/src
#       # universe -t
#
#   Then, to build just ls(1) for all archs, do this:
#
#       # universe bin/ls
#
#   Or to build with WARNS=6 and a subset of archs:
#
#       # universe bin/ls WARNS=6 i386 amd64 sparc64
#
#   When building is finished, a list will be printed that
#   indicates which architectures built successfully and
#   which failed.  The build log for the failed ones will
#   be kept in /tmp.  If you want to keep all build logs,
#   including successful ones, use the -k option.
#

ME="${0##*/}"
RC=0

error()
{
	echo "${ME}: $*" >&2
	exit 1
}

get_targets()
{
	TARGETS=$(make universe -V TARGETS)
	if [ $? -ne 0 -o -z "$TARGETS" ]; then
		error "Error executing 'make'. Make sure to run this in /usr/src."
	fi
}

usage()
{
	cat <<-tac >&2
		Usage:  $ME [-k] [-t] [<target> ...]
		        $ME [-k] <subdir> [<makevar>=<value> ...] [<target> ...]
		Options:  -k   keep log files even upon success
		          -t   build toolchain
		Please see the comments at the top of the script for details.
		Available targets (default is to build for all of them):
	tac
	get_targets
	echo "    $TARGETS" >&2
	exit 1
}

match()
{
	case "$1" in
		$2)	return 0 ;;
		*)	return 1 ;;
	esac
}

report()
{
	jot -s '' -b '=' 79
	echo "$ME finished."
	if [ -n "$SUCCESS" ]; then
		echo "Building $* was successful for the following arch(s):"
		echo "   $SUCCESS"
	fi
	if [ -n "$FAILURE" ]; then
		echo "Building $* *FAILED* for the following arch(s):"
		echo "   $FAILURE"
		RC=1
	fi
	if $KEEP_LOGS || [ -n "$FAILURE" ]; then
		echo "Logs are kept in this directory: $TMPDIR"
	else
		cleanup
	fi
}

if [ ! -f Makefile -o ! -f Makefile.inc1 ]; then
	#   Try to be clever ...
	TOPDIR=$(pwd)
	REST="${TOPDIR#*src}"
	REST="${REST#*/}"
	TOPDIR="${TOPDIR%/$REST}"
	cd $TOPDIR
	if [ ! -f Makefile -o ! -f Makefile.inc1 ]; then
		# Doh ...  Try /usr/src.
		cd /usr/src || error "Run this in the FreeBSD top-level source directory!"
	fi
fi

KEEP_LOGS=false
MAKE_TOOLCHAIN=false

while [ $# -gt 0 ]; do
	case "$1" in
		[!-]*)	break ;;
		--)	shift ; break ;;
		-*[!kt]*|-)	usage ;;
	esac
	match "$1" "-*k*" && KEEP_LOGS=true
	match "$1" "-*t*" && MAKE_TOOLCHAIN=true
	shift
done

if ! $MAKE_TOOLCHAIN; then
	if [ $# -lt 1 ]; then
		usage
	fi

	SUBDIR="$1"
	shift
	if [ ! -d "$SUBDIR" ]; then
		error "No such directory: $SUBDIR"
	fi

	#   Anything that looks like a variable assignment
	#   or an option is passed to make(1).

	MAKEARGS=""
	while [ $# -gt 0 ]; do
		case "$1" in
			*=*|-*)
				MAKEARGS="$MAKEARGS $1"
				shift
				;;
			*)
				break
				;;
		esac
	done
fi

get_targets
if [ $# -gt 0 ]; then
	# Check if targets exist.
	for T in "$@"; do
		case " $TARGETS " in
			*" $T "*)
				;;
			*)
				error "Unknown target \"$T\"."
				;;
		esac
	done
	TARGETS="$*"
fi

cleanup()
{
	if ! $KEEP_LOGS; then
		rm -rf $TMPDIR
	fi
}

unset MAKEOBJDIRPREFIX

TMPDIR=$(mktemp -d /tmp/universe.tmp.$$.XXXXXX) || error "mktemp(1) failed."
trap cleanup 1 2 3 15

if $MAKE_TOOLCHAIN; then
	FAILURE=""
	SUCCESS=""

	for T in $TARGETS; do
		LOG=$TMPDIR/toolchain_${T}.log

		make toolchain __MAKE_CONF=/dev/null TARGET=$T 2>&1 \
		    | tee $LOG

		if [ $? -eq 0 ]; then
			SUCCESS="$SUCCESS $T"
			if ! $KEEP_LOGS; then
				rm -f $LOG
			fi
		else
			FAILURE="$FAILURE $T"
		fi
	done

	report "the toolchain"
	exit $RC
fi

FAILURE=""
SUCCESS=""

for T in $TARGETS; do
	LOG=$TMPDIR/$(echo $SUBDIR | tr / _)_${T}.log
	COMMAND="make -C $SUBDIR obj clean && make -C $SUBDIR $MAKEVARS"

	echo "$COMMAND ; echo \$? > $TMPDIR/result" \
	    | make buildenv __MAKE_CONF=/dev/null TARGET=$T 2>&1 \
	    | tee $LOG

	if [ $(cat $TMPDIR/result) -eq 0 ]; then
		SUCCESS="$SUCCESS $T"
		if ! $KEEP_LOGS; then
			rm -f $LOG
		fi
	else
		FAILURE="$FAILURE $T"
	fi
	rm -r $TMPDIR/result
done

report "$SUBDIR"
exit $RC

#-- 
