#!/bin/bash
#
# --- T2-COPYRIGHT-NOTE-BEGIN ---
# This copyright note is auto-generated by ./scripts/Create-CopyPatch.
# 
# T2 SDE: scripts/Build-Target
# Copyright (C) 2004 - 2009 The T2 SDE Project
# Copyright (C) 1998 - 2003 ROCK Linux Project
# 
# More information can be found in the files COPYING and README.
# 
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; version 2 of the License. A copy of the
# GNU General Public License can be found in the file COPYING.
# --- T2-COPYRIGHT-NOTE-END ---
#
#   Run this command from the T2 SDE base directory as ./scripts/Build-Target
#   after running the ./scripts/Config and the now optional
#   ./scripts/Download commands.
# 
#   It compiles/builds all the packages and stores their binary package
#   ssuitable for distribution. 
# 
#   This script (and Build-Pkg) is T2 SDE's work-horse. It builds in a
#   chroot environment (stage 0..1) and goes through a number of build
#   stages (stage 2..9).
#

config=default
build_only_this_job=
daemon_mode=0
autodownload=1
options="$*"
downloadopt="-q"

while [ $# -gt 0 ] ; do
	case "$1" in
		-cfg)		config=$2 ; shift ;;
		-job)		build_only_this_job=$2 ; shift ;;
		-daemon)	daemon_mode=1 ;;
		-nodaemon)	daemon_mode=0 ;;
		-nodownload)	autodownload=0 ;;
		*)		echo "Usage: $0 [ -daemon ] [ -nodownload ] [ -cfg config ]" \
				     "[ -job <stage>-<package> ]" ; exit 1 ;;
	esac
	shift
done

# NOTE: ROCKCFG -> SDECFG automatized convertion
grep -q 'ROCKCFG' ./config/$config/config && 
	sed -i -e 's,ROCKCFG,SDECFG,g' ./config/$config/config

if [ "$daemon_mode" = 1 ] ; then
	. config/$config/config
	echo "Running $0 in the background (messages go to logfile only).."
	echo "Logfile: build/$SDECFG_ID/TOOLCHAIN/logs/build_target.log"
	nohup $0 $options -nodaemon > /dev/null 2> /dev/null < /dev/null &
	exit 0
fi

. scripts/parse-config
. scripts/functions.in

build_root="$base/build/$SDECFG_ID"
build_toolchain="$base/build/$SDECFG_ID/TOOLCHAIN"
build_logs="$build_toolchain/logs" ; mkdir -p "${build_logs}"
build_pkgs="$build_toolchain/pkgs" ; mkdir -p "${build_root}"

if [ "$SDECFG_PARANOIA_CHECK" = 1 ] ; then
	./scripts/Check-System || exit 1
fi

# Package Build loop - executed by build-target
#
pkgloop() {
	local x= y=

	if [ "$SDECFG_NOBROKENDEPS" = 1 ]; then
		nobrokendeps="-nobrokendeps"
	else
		nobrokendeps=""
	fi
	if [ -z "$build_only_this_job" ]; then

	  if [ "`ls ${build_root}/var/adm/logs/*.err 2> /dev/null`" ] ; then
		echo_header "Removing old error logs ..."
		for y in 0 1 2 3 4 5 6 7 8 9; do
			if [ "$SDECFG_RETRY_BROKEN" -eq 1 -o $y -le $SDECFG_CONTINUE_ON_ERROR_AFTER ]; then
				for x in ${build_root}/var/adm/logs/$y-*.err ; do
					if [ -f $x ]; then
						echo_status "Removing ${x#$build_root/} ..."
						rm -f $x
					fi
				done
			fi
		done
	  fi
	  if [ "`ls ${build_root}/var/adm/logs/*.out 2> /dev/null`" ] ; then
		echo_header "Removing old output logs ..."
		for x in ${build_root}/var/adm/logs/*.out ; do
			echo_status "Removing ${x#$build_root/} ..."
			rm -f $x
		done
	  fi

	  while
		next="`./scripts/Create-PkgQueue \
			-cfg "$config" -single $nobrokendeps`"
		[ "$next" ]
	  do
		pkgloop_package $next
	  done

	else
		rm -f "${build_root}"/var/adm/logs/${build_only_this_job}.log"
		rm -f "${build_root}"/var/adm/logs/${build_only_this_job}.err"
		next="$( awk 'BEGIN { FS=" "; }
		              $5 == "'${build_only_this_job#*-}'" && \
		              $2 ~ /'${build_only_this_job%%-*}'/ \
			      { $1="'${build_only_this_job%%-*}' 0";
		              print; exit; }' < config/$config/packages )"
		if [ ! "$next" ]; then
			echo_error "No job matching job spec: $build_only_this_job"
			exit 1
		fi

		pkgloop_package $next
		exit 0
	fi

	local pkglst=`mktemp` errors=0; rm -f src/invalid-files.lst
	echo_header "Searching for old lingering files ..."
	sed '/^[^X]/d ; s,.*=,,' config/$config/packages | cut -d' ' -f5 |
	if [ $SDECFG_PKGFILE_VER = 1 ] ; then
		while read p; do
			v=$( grep '^Package Name and Version:' \
				build/$SDECFG_ID/var/adm/packages/$p \
			        2>/dev/null | cut -f6 -d' ' )
			echo "$p-$v"
		done
	else
		cat
	fi > $pkglst
	for file in $( ls build/$SDECFG_ID/TOOLCHAIN/pkgs/ 2> /dev/null ) ; do
		x="$file"
		case $SDECFG_PKGFILE_TYPE in
		  tar.*)	x=${x%.$SDECFG_PKGFILE_TYPE} ;;
		  none)		: ;;
		esac
		if ! grep -qx "$x" $pkglst && ! test "$x" = packages.db ; then
			file="build/$SDECFG_ID/TOOLCHAIN/pkgs/$file"
			echo_error "$file should not be present" \
			           "(now in src/invalid-files.lst)!"
			mkdir -p src; echo "$file" >> src/invalid-files.lst
			errors=1
		fi
	done
	for dir in build/$SDECFG_ID/var/adm/{cache,dependencies,descs,flists,md5sums,packages} ; do
		for file in $( ls $dir 2> /dev/null ) ; do
			if [ $SDECFG_PKGFILE_VER = 1 ] ; then
				x="$file-"
			else 
				x="$file"
			fi	
			if ! grep -q "$x" $pkglst ; then
				echo_error "$dir/$file should not be present (now in src/invalid-files.lst)!"
				mkdir -p src; echo "$dir/$file" >> src/invalid-files.lst
				errors=1
			fi
		done
	done
	for file in $( ls build/$SDECFG_ID/var/adm/logs/ ) ; do
			x="`echo $file | sed -e 's/^.-//' -e 's/\.log//' -e 's/\.err//' -e s'/\.out//'`"
			if [ $SDECFG_PKGFILE_VER = 1 ] ; then
				x=$x-
			else
				x=$x
			fi

		if ! grep -q "$x" $pkglst ; then
			file="build/$SDECFG_ID/var/adm/logs/$file"
			echo_error "$file should not be present (now in src/invalid-files.lst)!"
			mkdir -p src; echo "$file" >> src/invalid-files.lst
			errors=1
		fi
	done
	[ $errors = 0 ] && echo_status "None found."
	rm $pkglst
}

# Process one line of output generated by Create-PkgQueue
#
pkgloop_package() {
	for x in stagelevel pkg_depnr pkg_stages pkg_pri pkg_tree \
	         pkg_name pkg_ver pkg_prefix pkg_extra
	do eval "$x=\$1" ; shift ; done

	[ "$build_only_this_job" -a \
	  "$stagelevel-$pkg_name" != "$build_only_this_job" ] && return

	[ $(expr "$pkg_stages" : ".*$stagelevel.*") -eq 0 ] && return
	pkg_laststage=$(echo "$pkg_stages" | sed "s,-,,g; s,.*\(.\),\1,")

	cmd_root="-root auto"
	[ $stagelevel -gt 1 ] && cmd_root="$cmd_root -chroot"

	if [ "$pkg_prefix" != "/" ] ; then
		cmd_prefix="-prefix $pkg_prefix"
	else cmd_prefix="" ; fi

	if [ "$autodownload" == 1 ]; then
		./scripts/Download -cfg $config $downloadopt $pkg_name
	fi

	cmd_buildpkg="./scripts/Build-Pkg -$stagelevel -cfg $config"
	cmd_buildpkg="$cmd_buildpkg $cmd_root $cmd_prefix $pkg_name"

	# Execute action handler
	if ! pkgloop_action && \
	   [ $stagelevel -le $SDECFG_CONTINUE_ON_ERROR_AFTER ]; then
		exit 1
	fi

	if [ ! -f ${build_root}/var/adm/logs/$stagelevel-$pkg_name.log -a \
	     ! -f ${build_root}/var/adm/logs/$stagelevel-$pkg_name.err ]
	then
		echo_header "Package build ended abnormally!"
		echo_error "Usually a package build creates either a *.log"
		echo_error "or a *.err file. Neither the 1st nor the 2nd is"
		echo_error "there. So I'm going to create a *.err file now"
		echo_error "and abort the build process."
		touch ${build_root}/var/adm/logs/$stagelevel-$pkg_name.err
		exit 1
	fi

	if [ $stagelevel -gt 0 -a $pkg_laststage -eq $stagelevel -a \
	     "$SDECFG_PKGFILE_TYPE" != none ]
	then
		if [ -f ${build_root}/var/adm/logs/$stagelevel-$pkg_name.err ]
		then echo_error "Creation of binary package isn't possible, \
because the package was not"
		     echo_error "built successfully in (at least) the current \
stage."
		else
			echo_header "Creating binary package file for ${pkg_name}."
			mkdir -p "${build_pkgs}"

			file=${pkg_name}
			if [ "$SDECFG_PKGFILE_VER" = 1 ]; then
				v="$( grep '^Package Name and Version:' \
				      ${build_root}/var/adm/packages/$pkg_name | cut -f6 -d' ' )"
				file="$file-$v"
			fi

			[[ $SDECFG_PKGFILE_TYPE = tar.* ]] &&
				file=$file.$SDECFG_PKGFILE_TYPE
			compressor=${SDECFG_PKGFILE_TYPE#tar.}
			case $compressor in
			  gz)	compressor=gzip ;;
			  bz2)	compressor=bzip2 ;;
			  lzo)	comrpessor=lzop ;;
			  # lzma et al. are named after the extension
			  # intermediate
			  gem)	compressor=bzip2 ; file=$file.tar.bz2 ;;
			esac

			echo_status "Building build/.../pkgs/$file"
			# sort var/adm before the rest - so they can be extracted, quickly
			( cd "$build_root/"
			  (grep    ' var/adm' var/adm/flists/$pkg_name
			   grep -v ' var/adm' var/adm/flists/$pkg_name) | cut -f2- -d' ' |
			  tar -cf- --no-recursion --files-from=- | $compressor
			) > ${build_pkgs}/$file.tmp
			mv ${build_pkgs}/$file{.tmp,}

			if [ "$SDECFG_PKGFILE_TYPE" = gem ] ; then
				echo_status "Building build/.../pkgs/${file%.tar.bz2}.gem"
				mine -C "$build_root/var/adm" $build_pkgs/$file $pkg_name \
				     $build_pkgs/${file%.tar.bz2}.gem.tmp
				mv $build_pkgs/${file%.tar.bz2}.gem{.tmp,}

				echo_status "Removing temporary tar.bz2."
				rm -f $build_pkgs/$file
			fi
		fi
	fi
}

# Action executed by pkgloop(). This function may be redefined
# before calling pkgloop().
#
pkgloop_action() {
	$cmd_buildpkg
}

# Try to umount any directories mounted by Build-Pkg -chroot
# if we are the last process using them.
#
umount_chroot() {
	exec 201> /dev/null
	if ! ( cd ${build_logs}; fuser *.log > /dev/null 2>&1 ); then
		echo_status "Unmounting loop mounts ..."
		umount -d -f    $build_toolchain/{loop,config,download} 2> /dev/null
		umount -d -f -l $build_toolchain/{loop,config,download} 2> /dev/null
		umount -d -f    $build_root/proc 2> /dev/null
		umount -d -f -l $build_root/proc 2> /dev/null
	fi
}

# must trap outside the group command
trap 'umount_chroot' EXIT

{
	ln -sf build_target_$$.log ${build_logs}/build_target.log
	./scripts/Build-Tools -1 -cfg $config
	_built=0
	for x in $( get_expanded ./target/%/build.sh $targetchain ); do
		if [ -f $x ]; then
			. $x
			_built=1
			break
		fi
	done
	[ $_built = 1 ] || echo_warning "No target/*/build.sh controlling the build!"
} 2>&1 201>> "${build_logs}/build_target_$$.log" | \
	tee -a "${build_logs}/build_target_$$.log"

