#!/bin/ash
# FatdogArm/Fatdog64 package build script
# Copyright (C) James Budiono, 2013, 2014, 2015
# License: GNU GPL Version 3 or later
# 
# This will build all packages, in the correct order, as specified
# by the pkglist. This script calls build-pkg.sh so many options in 
# build-pkg.sh is applicable here too.
#
# Note: this assumes that LFS Chapter 5 "tools" is already available 
# (LFS Chapter 5 can be built with bootstrap.sh)
#
# $1-command 
# command is install, build, download, remove (default is install)
#
# Package will be automatically rebuild/re-installed if the recipe is 
# newer than the compiled one.

export LANG=C # make it run a bit faster

### configuration settings (overridable)
#DRY_RUN= # if not empty, don't actually do it
PKGLIST=${PKGLIST:-build-pkglist}
BASE_DIR=""

DEF_PKGARCH=x86_64
PKGARCH=${PKGARCH:-$DEF_PKGARCH}
PKG_TYPE=${PKG_TYPE:-txz}
PKG_DIR=${PKG_DIR:-pkg}
PKG_DEPTH=5 # only look for package up to this depth

SRC_DIR=$(readlink -f ${SRC_DIR:-src})
OUTPUT_DIR=$(readlink -f ${OUTPUT_DIR:-output})
CMD=$1
INSTALLER=installpkg
REMOVEPKG=removepkg

### run-time variables
FINDPKG_CACHE= # filled in by main later

########### helpers ###########

# load our helper functions 
. ${0%/*}/build-lib.sh 

# $1-option, $* option variables, out: TEMP_INSTALL, TEMP_UNINSTALL
build_preprocess() {
	local p OPTION PKG PKG_FULL_PATH PKGNAME PKGVER PKGARCH PKGBUILD
	TEMP_INSTALL=""	TEMP_UNINSTALL=""
	
	for p; do
		case $p in
			%*) OPTION=$p; continue ;;
		esac
		
		# process args according to current options
		case $OPTION in
			%depends) # install temporary depedency, clearing other packages if need be
				find_pkg $PKG_DIR $p $FINDPKG_CACHE || continue # ignore packages not found
				if ! [ -e $BASE_DIR/var/log/packages/$PKG ]; then
					TEMP_INSTALL="$TEMP_INSTALL $PKG"
					#uninstall_only &&
					#TEMP_UNINSTALL="$TEMP_UNINSTALL $UNINSTALLED_PKG"
					[ $DRY_RUN ] && echo "temp-install $PKG" ||
					ROOT=$BASE_DIR $INSTALLER $OUTPUT_DIR/$PKG.$PKG_TYPE
				fi
				;;

			%removes) # temporarily removes some packages
				find_pkg $PKG_DIR $p $FINDPKG_CACHE || continue # ignore packages not found
				if [ -e $BASE_DIR/var/log/packages/$PKG ]; then
					uninstall_only &&
					TEMP_UNINSTALL="$TEMP_UNINSTALL $UNINSTALLED_PKG"
				fi
				;;
		esac
	done
}

# $1-option, $* option variables, $TEMP_INSTALL. $TEMP_UNINSTALL
build_postprocess() {
	local p
	
	# undo whatever was done in build_preprocess
	for p in $TEMP_INSTALL; do
		echo "temp-remove $p"
		[ $DRY_RUN ] || ROOT=$BASE_DIR $REMOVEPKG $OUTPUT_DIR/$p > /dev/null
	done
	for p in $TEMP_UNINSTALL; do
		[ $DRY_RUN ] && echo "install-back $p" ||
		ROOT=$BASE_DIR $INSTALLER $OUTPUT_DIR/$p.$PKG_TYPE
	done			
	TEMP_INSTALL="" TEMP_UNINSTALL=""
}


########### ACTIONS ###########


# $PKG, $PKG_FULL_PATH, $@-options
build_install() {
	#echo build install $PKG; return
	if ! [ -e $BASE_DIR/var/log/packages/$PKG ] || 
	   [ $PKG_FULL_PATH/recipe -nt $BASE_DIR/var/log/packages/$PKG ];
	then
			#uninstall_only && 
			build_only "$@" &&
			if [ $DRY_RUN ]; then
				echo install $PKG
			else
				[ -e $OUTPUT_DIR/$PKG.$PKG_TYPE ] &&
				ROOT=$BASE_DIR $INSTALLER $OUTPUT_DIR/$PKG.$PKG_TYPE
			fi
	fi
}

# $PKG $PKG_FULL_PATH, $@-options
build_only() {
	local ret
	#echo build only $PKG; return
	if ! [ -e $OUTPUT_DIR/$PKG.$PKG_TYPE ] ||
	   [ $PKG_FULL_PATH/recipe -nt $OUTPUT_DIR/$PKG.$PKG_TYPE ];
	then
		build_preprocess "$@"
		[ $DRY_RUN ] && echo build $PKG ||
		./build-pkg.sh $PKG; ret=$?
		build_postprocess "$@"
	fi
	return $ret
}

# $PKG
download_only() {
	#echo download only $PKG; return
	unset pkg_download
	[ -e ./functions.sh ] && . ./functions.sh
	. $PKG_FULL_PATH/recipe
	type pkg_download > /dev/null || return 0
	if ! [ -s $SRC_DIR/$TARBALL ]; then
		[ $DRY_RUN ] && echo download $PKG ||
		pkg_download $SRC_DIR $TARBALL 
	fi
}

# $PKG, out: UNINSTALLED_PKG
uninstall_only() {
	UNINSTALLED_PKG=""
	local PKG=$PKG p # find the base pkgname
	PKG=${PKG%-*}; PKG=${PKG%-*}; PKG=${PKG%-*}; # strip build, arch, version
	for p in $BASE_DIR/var/log/packages/${PKG}-[0-9]*; do # find actual installed pkgname
		PKG=${p##*/}
		
		#echo uninstall only $PKG; return
		if [ -e $BASE_DIR/var/log/packages/$PKG ]; then
			UNINSTALLED_PKG=$PKG
			echo uninstall $PKG
			[ $DRY_RUN ] || ROOT=$BASE_DIR $REMOVEPKG $PKG > /dev/null
		fi
	done
	return 0
}

# $PKG
bootstrap() {
	download_only
	[ -e $BASE_DIR/var/log/packages/$PKG ] && return 0
	[ $DRY_RUN ] && echo bootstrapping $PKG ||
	#mkdir -p $BASE_DIR &&
	ROOT=$BASE_DIR $INSTALLER $SRC_DIR/$PKG.$PKG_TYPE
}

# $1-input file
process() {
	local PKGLIST=$1 line
	while read -r line; do
		set -- ${line%%#*}
		[ -z $1 ] && continue # empty line, skip

		# process directive
		case $1 in
			%exit|%quit)
				echo "Exiting because of %exit directive."
				exit ;;	
			%return)
				return ;;
			%include)
				process $2;
				continue ;;
			%echo)
				shift
				echo "$@"
				continue ;;
		esac
		
		# process standard pkg-build
		PKG=$1; shift; CCMD=${CMD:-$1}; shift
		find_pkg $PKG_DIR $PKG $FINDPKG_CACHE || exit # return $PKG $PKG_FULL_PATH PKGNAME PKGVER PKGARCH PKGBUILD
		case $CCMD in
			""|install) build_install "$@" ;;
			build) build_only "$@" ;; 
			download) download_only ;;			
			uninstall|remove) uninstall_only ;;
			bootstrap) bootstrap ;;
			help|-h|--help) 
				echo "[PKGLIST=pkglist] ${0##*/} [build|download|install|uninstall]"
				exit ;;
			*) echo "unknown command $CCMD for $PKG, ignored ..." ;;
		esac || { echo "$PKG failed to build, stopping."; exit; }		
	done < $PKGLIST
}

### main
FINDPKG_CACHE=$(create_find_pkg_cache $PKG_DIR $PKG_DEPTH)
trap 'rm -f $FINDPKG_CACHE; exit' 0 INT HUP TERM
export FINDPKG_CACHE # for use by build-pkg.sh
process $PKGLIST

