#!/bin/bash
#This bash script calls the nightlyrun.m matlab file to run our nightly test decks. 
#It then processes the results and sends an email to the Ice developpers.

#some functions
function timer() #{{{
{
	if [[ $# -eq 0 ]]; then
		echo $(date '+%s')
	else
		local  stime=$1
		etime=$(date '+%s')

		if [[ -z "$stime" ]]; then stime=$etime; fi

		dt=$((etime - stime))
		ds=$((dt % 60))
		dm=$(((dt / 60) % 60))
		dh=$((dt / 3600))
		printf '%d:%02d:%02d' $dh $dm $ds
	fi
} #}}}
function todaydate() #{{{
{
	suffix=`date | awk '{printf("%s-%s-%s  %s",$2,$3,$6,$4);}'`			 
	echo $suffix;			 
} #}}}
function host_name() #{{{
{
	#return host name depending on the OS
	if [ "$1" = "win7" ] 
	then
		HOST_NAME=`hostname | sed 's/-//g'`;
	else
		HOST_NAME=`hostname -s | sed 's/-//g'`;
	fi
	echo $HOST_NAME;
} #}}}
function pause() #{{{
{
pid=`ps aux -W | grep $1 | awk '{printf("%s\n",$1);}'`

while [ -n "$pid" ]
do
	pid=`ps aux -W | grep $1 | awk '{printf("%s\n",$1);}'`
done
}
#}}}

#Get configuration
#Source config file{{{
if [ $# -ne 1 ];
then
	#no config file specified: exit
	echo "no config file specified. Exiting..." >&2 # Error message to stderr.
	exit 1
fi
if [ ! -f "$1" ]
then
	echo "File $1 not found!" >&2   # Error message to stderr.
	exit 1
fi 
source $1;
#}}}
#Initialize variables {{{
TODAY=$(todaydate);
OS=$(uname -s)
if [[ $OS == "CYGWIN_NT-6.1-WOW64" ]]; then 
	OS="win7";
fi
HOST_NAME=$(host_name $OS);
START_TIME=$(timer);
ISSM_RELEASE=$(basename $(echo $REPOSITORY));
USER=$(whoami);
INIT_PATH=$(pwd);
#}}}

#Installation ISSM
#create matlab's installation sript {{{
cat << END > $ISSM_DIR/externalpackages/matlab/install.sh
#!/bin/bash
rm -rf install
ln -s $MATLAB_PATH install
END
#}}}
#install/copy/none external packages    (ISSM_EXTERNALPACKAGES){{{
if [ "$ISSM_EXTERNALPACKAGES" == "install" ]
then
	
	cd $ISSM_DIR/externalpackages

	#number of packages: 
	NUMPACKAGES=$(($(echo $EXTERNALPACKAGES | wc -w )/2))

	for ((i=1;i<=$NUMPACKAGES;i++))
	do
		NUM1=$((2*$i-1))
		NUM2=$((2*$i))
		PACKAGENAME=$(echo $EXTERNALPACKAGES | cut -d " " -f $NUM1-$NUM1)
		PACKAGEINST=$(echo $EXTERNALPACKAGES | cut -d " " -f $NUM2-$NUM2)

		cd $PACKAGENAME

		#tricky part here. We do not want to reinstall this package if it's already installed
		#and the svn file which does the install has not be modified! To keep track of 
		#this, we check the current svn version against the "last changed" revision number.  If they 
		#are the same, we reinstall the package. 
		current_version=`svnversion`
		last_changed_version=`svn info $PACKAGEINST | grep "Last Changed Rev" | awk '{printf("%s\n",$4);}'`

		if [[ $current_version == $last_changed_version ]]; then 
			#go ahead and reinstall. 
			echo "For $PACKAGENAME: svn current_version  is $current_version and last changed version is $last_changed_version"
			echo "Triggering new install of $PACKAGENAME"
			install_test=1
		else
			#ok, we want to skip, unless the package is not installed: 
			if [ -d install ]; then 
				#could be empty, signaling a failed previous install: 
				if [ "$(ls -A install)" ];then
					echo "For $PACKAGENAME: svn current_version  is $current_version and last changed version is $last_changed_version"
					echo "and install directory exists, so skipping install of $PACKAGENAME"
					install_test=0;
				else
					echo "For $PACKAGENAME: svn current_version  is $current_version and last changed version is $last_changed_version"
					echo "and install directory exists, however, it is empty, so triggering install of $PACKAGENAME"
					install_test=1;
				fi
			else
				echo "For $PACKAGENAME: svn current_version  is $current_version and last changed version is $last_changed_version"
				echo "However, install directory does not exist, so triggering install of $PACKAGENAME"
				install_test=1;
			fi
		fi

		if [[ $install_test == 1 ]]; then 
			echo "======================================================";
			echo "       Installing $PACKAGENAME                        ";
			echo "======================================================";
			./$PACKAGEINST |  tee compil.log
			if [ $? -ne 0 ]; then
				echo "======================================================";
				echo "    ERROR: installation of $PACKAGENAME failed        ";
				echo "======================================================";
				#erase install directory, so that next time, we still try and compile this!
				rm -rf install
			fi
			source $ISSM_DIR/etc/environment.sh
		else
			echo "======================================================";
			echo "       Skipping install of $PACKAGENAME                        ";
			echo "======================================================";
			source $ISSM_DIR/etc/environment.sh #for good measure :)
		fi
		cd ..
	done

elif [ "$ISSM_EXTERNALPACKAGES" == "copy" ]
then
	cd $ISSM_DIR
	rm -rf externalpackages
	cp -Rf $EXTERNALPACKAGESDIR ./
elif [ "$ISSM_EXTERNALPACKAGES" == "link" ]
then
	cd $ISSM_DIR
	rm -rf externalpackages
	ln -s  $EXTERNALPACKAGESDIR  .
elif [ "$ISSM_EXTERNALPACKAGES" == "none" ]
then
	echo "Skipping external packages installation"
else
	echo "ISSM_EXTERNALPACKAGES supported values are: install, copy and none. Exiting..." >&2 # Error message to stderr.
	exit 1
fi
source $ISSM_DIR/etc/environment.sh
#}}}
#ISSM compilation yes/no                (ISSM_COMPILATION) {{{
if [ "$ISSM_COMPILATION" == "yes" ]
then
	cd $ISSM_DIR
	make uninstall
	make clean
	make distclean
	./scripts/automakererun.sh
	cat > configure.sh << EOF
./configure $ISSM_CONFIG
EOF
	chmod 700 configure.sh
	./configure.sh

	#4: compile and install ISSM
	if [ $NUMCPUS_INSTALL -gt 1 ]
	then
		echo "Making with " $NUMCPUS_INSTALL " cpus"
		make -j $NUMCPUS_INSTALL install
	else
		make install
	fi
	if [ $? -ne 0 ]; then 
		echo "ISSM_COMPILATION failed!"
		exit 1
	fi
elif [ "$ISSM_COMPILATION" == "no" ]
then
	echo "Skipping ISSM compilation"
else
	echo "ISSM_COMPILATION supported values are: yes and no. Exiting..." >&2 # Error message to stderr.
	exit 1
fi
#}}}
echo "Cleaning up execution directory"
rm -rf $ISSM_DIR/execution/*

#Prepare info.log
#{{{
rm -rf $ISSM_DIR/nightlylog
mkdir  $ISSM_DIR/nightlylog
INSTALL_TIME=$(timer)
ELAPSED=$(timer $START_TIME)
VERSION=$(svnversion $ISSM_DIR)
cat << END > $ISSM_DIR/nightlylog/info.log
name:      $(echo $NAME)
today:     $(echo $TODAY)
user:      $(echo $USER)
host:      $(echo $HOST_NAME)
OS:        $(echo $OS)
release:   $(echo $ISSM_RELEASE)
init_path: $(echo $INIT_PATH)
is_matlab: $(echo $MATLAB_TEST)
is_python: $(echo $PYTHON_TEST)
elapsed_install: $(echo $ELAPSED)
version: $(echo $VERSION)
END
#}}}

#matlab tests
if [ $MATLAB_TEST -eq 1 ]; then
#Launch all tests on different cpus {{{
MATLAB_START_TIME=$(timer);
for (( i=1;i<=$NUMCPUS_RUN;i++ ))
do
	#Launch matlab and the nightly run script
	cat > $ISSM_DIR/nightlylog/matlab_run$i.m << EOF
	warning off %necessary to avoid a info.log of several Go for parallel runs
	try,
	$(if [ "$MATLAB_NROPTIONS" = ""  ]
	then
		echo "runme('output','nightly','rank',$i,'numprocs',$NUMCPUS_RUN);"
	else
		echo "runme($MATLAB_NROPTIONS,'output','nightly','rank',$i,'numprocs',$NUMCPUS_RUN);"
	fi
	)
	catch me,
		%An error occured, get report and exit
		message=getReport(me)
		directory=strsplit(pwd,'/');
		fid=fopen([issmdir '/nightlylog/matlaberror.log'], 'at');
		fprintf(fid,'\nMatlab error occured in: %s\n\n',directory{end});
		fprintf(fid,'%s',message);
		fclose(fid);
	end
	disp('MATLABEXITEDCORRECTLY');
	exit
EOF
	cd $ISSM_DIR/test/NightlyRun
	matlab -nojvm -nosplash -r "addpath $ISSM_DIR/src/m/dev; devpath; addpath $ISSM_DIR/nightlylog/; matlab_run$i" -logfile $ISSM_DIR/nightlylog/matlab_log$i.log &
done

#wait until matlab closes
if [ "$OS" = "win7" ]; then
	pause MATLAB
else
	wait
fi

#concatenate reports
cd $ISSM_DIR/nightlylog/
rm matlab_log.log
for (( i=1;i<=$NUMCPUS_RUN;i++ ))
do
	cat matlab_log$i.log >> matlab_log.log
done

#filter out windows characters: 
cat matlab_log.log | tr -cd '\11\12\40-\176' > matlab_log.log2 && mv matlab_log.log2 matlab_log.log

#}}}
#Complete info.log {{{
if [ $(cat matlab_log.log | grep "MATLABEXITEDCORRECTLY" | wc -l) -eq $NUMCPUS_RUN ]
then
	MATLABCRASH=0
else
	MATLABCRASH=1
fi
ELAPSED=$(timer $MATLAB_START_TIME)
cat << END >>  $ISSM_DIR/nightlylog/info.log
elapsed_matlab: $(echo $ELAPSED)
matlab_crash:   $(echo $MATLABCRASH)
END
#}}}
fi

#python tests
if [ $PYTHON_TEST -eq 1 ]; then
#Launch all tests on different cpus {{{
PYTHON_START_TIME=$(timer);
export PYTHONSTARTUP=$ISSM_DIR/src/m/dev/devpath.py
for (( i=1;i<=$NUMCPUS_RUN;i++ ))
do
	cd $ISSM_DIR/test/NightlyRun
	./runme.py --output=nightly --rank=$i --numprocs=$NUMCPUS_RUN $PYTHON_NROPTIONS 2>&1 > $ISSM_DIR/nightlylog/python_log$i.log &
done

#wait until python closes
if [ "$OS" = "win7" ]; then
	pause MATLAB
else
	wait
fi

#concatenate reports
cd $ISSM_DIR/nightlylog/
rm python_log.log
for (( i=1;i<=$NUMCPUS_RUN;i++ ))
do
	cat python_log$i.log >> python_log.log
done
#}}}
#Complete info.log {{{
if [ $(cat python_log.log | grep "PYTHONEXITEDCORRECTLY" | wc -l) -eq $NUMCPUS_RUN ]
then
	PYTHONCRASH=0
else
	PYTHONCRASH=1
fi
ELAPSED=$(timer $PYTHON_START_TIME)
cat << END >>  $ISSM_DIR/nightlylog/info.log
elapsed_python: $(echo $ELAPSED)
python_crash:   $(echo $PYTHONCRASH)
END
#}}}
fi

#complete info.log
#{{{
ELAPSED=$(timer $START_TIME)
cat << END >>  $ISSM_DIR/nightlylog/info.log
elapsed_total:  $(echo $ELAPSED)
END
#}}}

#process logs to be junit compatible
#{{{
cd $ISSM_DIR/nightlylog/
source $ISSM_DIR/externalpackages/shell2junit/install/sh2ju.sh
juLogClean

if [ $MATLAB_TEST -eq 1 ]; then
	#number tests:
	numtests=`cat matlab_log.log  | grep "\-\-\-\-\-\-\-\-starting" | wc -l`
	testlist=`cat matlab_log.log  | grep "\-\-\-\-\-\-\-\-starting" | sed 's/----------------starting://g'  | sed 's/-//g'`

	#look through numtests:
	for i in `echo $testlist`
	do
		juLog  -test=MATLAB-$i -name=Error -error=ERROR awk "/starting:$i/{flag=1;next}/finished/{flag=0} flag{print}" matlab_log.log
		juLog  -test=MATLAB-$i -name=Failure -error=FAILURE awk "/starting:$i/{flag=1;next}/finished/{flag=0} flag{print}" matlab_log.log
	done
fi
if [ $PYTHON_TEST -eq 1 ]; then
	#number tests:
	numtests=`cat python_log.log  | grep "\-\-\-\-\-\-\-\-starting" | wc -l`
	testlist=`cat python_log.log  | grep "\-\-\-\-\-\-\-\-starting" | sed 's/----------------starting://g'  | sed 's/-//g'`

	#look through numtests:
	for i in `echo $testlist`
	do
		juLog  -test=PYTHON-$i -name=Error -error=ERROR awk "/starting:$i/{flag=1;next}/finished/{flag=0} flag{print}" python_log.log
		juLog  -test=PYTHON-$i -name=Failure -error=FAILURE awk "/starting:$i/{flag=1;next}/finished/{flag=0} flag{print}" python_log.log
	done
fi
#}}}
