#!/bin/sh
# Copyright 2012 FARGOS Development, LLC
# Invoke make within a sandbox; makefile can be retrieved from
# a backing tree.
# $Id$
originDir=`dirname $0`
clearLDPATH=${CLEAR_LD_PATH:-1}
if test "${clearLDPATH}" = "1"
then
	# We don't expect any build tools to require a special LD_LIBRARY_PATH
	unset LD_LIBRARY_PATH
fi

if test -z "${SB_MAKE_COMMAND}"
then
	SB_MAKE_COMMAND=`which --skip-alias make`
	export SB_MAKE_COMMAND
fi
makeCmd="${SB_MAKE_COMMAND}"

# Normally, make sets RM to "rm -f", which causes the PATH to be searched
RM="${RM:-/bin/rm -f}"; export RM
searchList=""
makeArgs=""
curDir=`pwd`
parallel=""
outSync="${DEFAULT_MAKE_OUTPUT_SYNC:--output-sync=recurse}"
autoRegen=${SBMAKE_AUTOREGEN:-0}
makeLevel=${MAKELEVEL:-0}
vimRCset=${MYVIMRC:+1}
noTimestamp=${vimRCset:-0}

while test $# -gt 0
do
	case $1 in
	-h | -help | --help)
		printf "usage: %s [-auto] [{-j jobs|-l load}] [-m makeCmd] [-C dir] [-f file][...]\n" $0 >&2
		exit 1
		;;
	-auto)
		autoRegen=1
		;;
	-noauto)
		autoRegen=0
		;;
	-notimestamp)
		noTimestamp=1
		;;
	-f)
		searchList="${searchList}${searchList:+ }$2"
		shift
		;;
	-C)
		cd "${2}"
		${originDir}/colorText -green `basename $0`": Enterered" `pwd`", left ${curDir}" -reset
		curDir=`pwd`
		shift
		;;
	-m)
		makeCmd="${2}"
		shift
		;;
	--output-sync=* | -O)
		outSync="${1}"
		shift
		;;
	-j) # value passed as second argument
		parallel="--jobs=${2}"
		shift
		;;
	-j[0-9]*) # number concatenated with flag
		num=`expr substr $1 3 '(' length $1 - 2 ')'`
		parallel="--jobs=${num}"
		;;
	-l)
		parallel="--load-average=${2}"
		shift
		;;
	*)
		makeArgs="${makeArgs}${makeArgs:+ }$1"
		;;
	esac
	shift
done

SBMAKE_AUTOREGEN=${autoRegen}; export SBMAKE_AUTOREGEN
# export name of this program
SBMAKE_PROG="${0}"; export SBMAKE_PROG

# If no specification and topmost make, use available CPUs
if test -z "${parallel}" -a ${makeLevel} = "0"
then
	# TODO:  Linux-specific, not portable
	processors=`getconf _NPROCESSORS_ONLN`
	pages=`getconf _PHYS_PAGES`
	maxJobsForMemory=`expr ${pages} / 500000`
	parallelJobs=`expr ${processors:-1} - 1`
	if test ${parallelJobs} -gt ${maxJobsForMemory}
	then
		parallelJobs="${maxJobsForMemory}"
	fi
	if test ${parallelJobs} -lt 2
	then # lower bound is 2
		parallelJobs=2
	fi
	parallel="-j ${parallelJobs}"
fi

if test -z "${searchList}"
then
	searchList="sb.Makefile Makefile makefile"
fi

for searchFor in ${searchList} # list of files names
do
	makeFile=`${originDir}/findFileInSB -q -d . -all ${searchFor}`
	if test -n "${makeFile}"
	then
		break
	fi
done

if test -z "${makeFile}"
then
	${originDir}/colorText -red "${0}: cannot locate any ${searchList} in sandbox in" `pwd` -reset >&2
	if test ! -t 2
	then
		ttyName=`tty`
		if test -n "${ttyName}"
		then
			${originDir}/colorText -red "${0}: cannot locate any ${searchList} in sandbox in" `pwd` -reset > ${ttyName}
		fi
	fi
	exit 2
fi

make_fileName=`basename ${makeFile}`
make_prefix=`expr substr "${make_fileName}" 1 3`
if test "${make_prefix}" = "sb."
then
	orig_make_fileName=`expr substr "${make_fileName}" 4 '(' length "${make_fileName}" - 3 ')'`
	# To match sb.Makefile derived from "makefile" rather than "Makefile"
	# convert first character to lowercase and see if filename is different
	altFilePrefix=`expr substr ${orig_make_fileName} 1 1 | tr '[:upper:]' '[:lower:]'`
	altFileSuffix=`expr substr ${orig_make_fileName} 2 '(' length ${orig_make_fileName} - 1 ')'`
	altFile="${altFilePrefix}${altFileSuffix}"
	if test "${altFile}" = "${orig_make_fileName}"
	then # same, so we do not look for it
		altFile=""
	fi
	for searchFor in ${orig_make_fileName} ${altFile} # list of files names
	do
		origMakeFile=`${originDir}/findFileInSB -q -d . -all ${searchFor}`
		if test -n "${origMakeFile}"
		then
			break
		fi
	done
	if test -n "${origMakeFile}"
	then # found original Makefile
		if test ${makeFile} -ot ${origMakeFile}
		then
			${originDir}/colorText -red "WARNING: ${makeFile} is older than ${origMakeFile}" -reset >&2
			if test ${autoRegen} -eq 0
			then
				${originDir}/colorText -cyan 'Suggest:  genNewMakefile -f' ${origMakeFile} '>' sb.${orig_make_fileName} -reset >&2
			else
				${originDir}/colorText -yellow "Attempting automatic regeneration of ${makeFile} from ${origMakeFile}" -reset >&2
				makeFile="sb.${orig_make_fileName}"
				${originDir}/colorText -cyan "Invoking genNewMakefile -f ${origMakeFile} -o sb.${orig_make_fileName}" -reset
				${originDir}/genNewMakefile -f ${origMakeFile} -o sb.${orig_make_fileName}
				if test sb.${orig_make_fileName} -ot ${origMakeFile}
				then # nothing changed
					 ${originDir}/colorText -red "${0}:  FAILED to regenerate ${makeFile}" -reset >&2
					exit 1
				fi
			fi
		fi
	fi
fi

# found file
if test ${noTimestamp} -eq 0
then
	nowTime=`date +%T`
	startSeconds=`date +%s`
	${originDir}/colorText -blue "${nowTime}" In ${curDir} Invoking ${makeCmd} ${parallel} ${outSync} -f ${makeFile} ${makeArgs} -reset
fi
trap "${originDir}/cleanCompletionLocks" SIGINT SIGQUIT SIGTERM
/bin/nice ${makeCmd} ${parallel} ${outSync} -f ${makeFile} ${makeArgs}
rc=$? # save exit status from make
if test ${rc} -ne 0
then
	if test "${makeLevel}" = "0"
	then
		${originDir}/colorText -red "Cleaning locks on error exit" -reset
		${originDir}/cleanCompletionLocks
		if test -t 0
		then # standard in associated with terminal
			ttyName=`tty`
			if test -n "${ttyName}"
			then
			${originDir}/colorText -red "${makeCmd} -f ${makeFile} ${makeArgs}" -blink "exited with error code ${rc}" -reset > ${ttyName}
			fi
		fi
	else
		${originDir}/colorText -red "In nested make at level ${makeLevel} in ${curDir} with path ${MAKEFILE_LIST}, deferring lock cleanup." -reset
	fi
fi
if test ${noTimestamp} -eq 0
then
	nowSeconds=`date +%s`
	duration=`expr ${nowSeconds} - ${startSeconds}`
	nowTime=`date +%T`
	${originDir}/colorText -cyan "${nowTime} In ${curDir} build ${makeCmd} -f ${makeFile} ${makeArgs} required ${duration} seconds" -reset
fi
exit ${rc} # return exit status from make
