#!/bin/bash

rebuild_all_version=0

unset processes modules_files

#
# functions
#

isMemberOf() {
	local i target
	target="$1"
	shift 1
	for i in $@; do
		[[ "$target" == "$i" ]] && return 0
	done
	return 1
}

printHelpAndExit(){
	[[ -n "$*" ]] && echo $* && echo
cat << __EOF__
usage: rebuild_all [options]
	-a action                Set the action or package manager.
	-A                       List available actions.
	-m module1:module2...    Set modules to check for broken packages, a colon separated list.
	-M                       List available modules.
	-V exact|best|slot       Set, which version of the broken package should be built.
	-p                       Use pretend option for package managers.

	-d		 				Debug using set -xv.
	-v                      Print version.
	-h                      Print help.
__EOF__

	exit
}

cleanup_on_die(){
	[[ -n "${processes[*]}" ]] && kill ${processes[*]}
	rm -f ${modules_files[*]} ${modules_errorfiles[*]}
}

get_exact_version () {
	local i
	for i in $*; do
		echo $(echo $i | sed 's/^/=/')
	done
}

strip_version () {
	local i
	for i in $*; do
		echo $(echo $i | sed 's/-[0-9]\+\(\.[0-9]\+\)*[a-z]\?\(_\(\(alpha\)\|\(beta\)\|\(pre\)\|\(rc\)\|\(p\)\)[0-9]*\)\?\(-r[0-9]*\)\?$//')
	done
}

get_slot () {
	local i
	for i in $*; do
			echo "$(strip_version $i)":$(<"/var/db/pkg/${i}/SLOT")
	done
}

trap "cleanup_on_die; exit" SIGHUP SIGINT SIGQUIT SIGABRT SIGTERM

#
# settings
#

#default modules, all present
modules_path="/etc/rebuild-all/modules/"
action_path="/etc/rebuild-all/actions/"

#TODO
action="portage"

#exact, best, slot TODO
rebuild_version="exact"

pretend=no

[[ -f /etc/rebuild-all/rebuild-allrc ]] && . /etc/rebuild-all/rebuild-allrc

available_rebuild_version=(exact best slot)
available_modules=($(ls "${modules_path}"))
available_action=($(ls "${action_path}"))
[[ -z "$modules" ]] && modules=(${available_modules[*]})

while getopts "Aa:Mm:V:pdvh" optionName; do
	case "$optionName" in
			a) action="$OPTARG";;
			A) echo "${available_action[*]}"; exit 0;;
			m) modules=($(echo "$OPTARG" | sed 's/:/ /g'));;
			M) echo "${available_modules[*]}"; exit 0;;
			V) rebuild_version="$OPTARG";;
			p) pretend=yes;;
#default stuff
			d) set -xv;;
			v) echo rebuild_all version "$reabuild_all_version" && exit;;
			h) printHelpAndExit;;
			[?]) printHelpAndExit bad_option "$badOptionHelp";;
	esac
done

#check module availability etc.
for i in ${modules[*]}; do
	isMemberOf $i ${available_modules[*]} || printHelpAndExit unknown_module $i
done
	
isMemberOf $rebuild_version ${available_rebuild_version[*]} ||
	printHelpAndExit unknown_rebuild_version $rebuild_version

isMemberOf $action ${available_action[*]} ||
	printHelpAndExit unknown_action $action

#
# functionality
#

. "${action_path}/${action}"

[[ 0 == ${#modules[*]} ]] && exit 0

for ((i=0;i<${#modules[*]};i++)) do
	modules_files[$i]=$(mktemp)
	modules_errorfiles[$i]=$(mktemp)
	"${modules_path}/${modules[$i]}" find_broken ${modules_files[$i]} ${modules_errorfiles[$i]} &
	processes=(${processes} $?)
done

wait
unset processes

#check for errors
for ((i=0;i<${#modules[*]};i++)) do
	[[ -n "$(<${modules_errorfiles[$i]})" ]] && echo module "${modules[$i]}" failed with "$(<${modules_errorfiles[$i]})" && cleanup_on_die && exit 1
done

packagesToRebuild=$([[ -n "${modules_files[*]}" ]] && cat ${modules_files[*]})
cleanup_on_die
test -z "${packagesToRebuild[*]}" && exit 0

case "$rebuild_version" in
	exact) rebuild_targets=($(get_exact_version ${packagesToRebuild[*]}));;
	slot) rebuild_targets=($(get_slot ${packagesToRebuild[*]}));;
	best) rebuild_targets=($(strip_version ${packagesToRebuild[*]}));;
	*) echo internal error && exit 1;;
esac

if [[ yes == "$pretend" ]]; then
	pretend_rebuild ${rebuild_targets[*]}
else
	rebuild ${rebuild_targets[*]}
fi

