#!/bin/bash

# Purpose: To discover which of your installed packages is broken
# with modular X. Uses a binary search and greps emerge output for blocks on
# X. Will work even if multiple packages are not ported to modular X.

PORTDIR=$(/usr/bin/portageq envvar PORTDIR)
PKGFILE="/var/lib/portage/world"
CATEGORY=$1

decho() {
	if [[ -n "$DEBUG" ]]; then
		echo $@
	fi
}

usage() {
	echo
	echo "${0##*/} [ CATEGORY ]"
	echo "  Discover packages that haven't been ported to modular X dependencies."
	echo "  By default, acts on ${PKGFILE}. If passed CATEGORY,"
	echo "  it will check ${PORTDIR}/CATEGORY instead."
	exit 1
}

# Get all the packages in a given category
get_category_packages() {
	local PORTDIR=$1
	local CATEGORY=$2
	local PKG PKGS
	pushd $PORTDIR &> /dev/null
	for PKG in $(ls $CATEGORY); do
		if [[ -d ${CATEGORY}/${PKG} ]]; then
			PKGS="$PKGS ${CATEGORY}/${PKG}"
		fi
	done
	popd &> /dev/null

	echo $PKGS
}

# Returns half of list it was given. Which half determined by whether $1
# is set to 1 or 2
# **char get_half(char half, **char full_array)
get_half() {
	local HALF=$1
	declare -a ARRAY
	ARRAY=( $2 )
	local i

	if [[ $HALF -ne 1 ]] && [[ $HALF -ne 2 ]]; then
		echo "Invalid argument for char half"
		echo "Valid arguments are 1 or 2."
		exit 1
	fi

	local FULL_SIZE=${#ARRAY[@]}
	local HALF_SIZE=$(( FULL_SIZE / 2 ))

	if [[ $HALF -eq 1 ]]; then
		START="0"
		STOP=$(( HALF_SIZE - 1 ))
	else
		START=$(( HALF_SIZE ))
		STOP=$(( FULL_SIZE - 1 ))
	fi

	for (( i = START; i <= STOP; i++ )); do
		HALF_ARRAY[$i]=${ARRAY[$i]}
	done

	echo ${HALF_ARRAY[@]}
}

# Takes list of packages, returns list of those blocking modular X
# **char find_blocker(**char full_array)
find_blocker() {
	declare -a LIST FIRST_HALF SECOND_HALF
	LIST=( $1 )
	local LISTSIZE=${#LIST[@]}
	local EMERGE_FIRST_HALF EMERGE_SECOND_HALF EMERGE_FH_EXIT EMERGE_SH_EXIT
	local EMERGE_FH_EXIT="1"
	local EMERGE_SH_EXIT="1"
	local FAILED_PKG

	# Return the broken modular package
	if [[ $LISTSIZE -le 1 ]]; then
		echo ${LIST[@]}
		return 0
	fi

	FIRST_HALF=( $(get_half 1 "${LIST[*]}") )
	SECOND_HALF=( $(get_half 2 "${LIST[*]}") )
	decho FIRST_HALF=${FIRST_HALF[@]}
	decho SECOND_HALF=${SECOND_HALF[@]}

	while [[ $EMERGE_FH_EXIT -ne 0 ]]; do
		EMERGE_FIRST_HALF=$(emerge -Dp ${FIRST_HALF[@]})
		EMERGE_FH_EXIT=$?
		if [[ $EMERGE_FH_EXIT -eq 0 ]]; then
			break
		fi
		FAILED_PKG="$(echo "$EMERGE_FIRST_HALF" \
			| grep "All ebuilds that could satisfy" \
			| cut -d\" -f2)"
		decho FAILED_PKG=$FAILED_PKG
		for (( i = 0; i < ${#FIRST_HALF[@]}; i++ )); do
			if [[ ${FIRST_HALF[$i]} = $FAILED_PKG ]]; then
				FIRST_HALF[$i]=""
			fi
		done
	done
	while [[ $EMERGE_SH_EXIT -ne 0 ]]; do
		EMERGE_SECOND_HALF=$(emerge -Dp ${SECOND_HALF[@]})
		EMERGE_SH_EXIT=$?
		if [[ $EMERGE_SH_EXIT -eq 0 ]]; then
			break
		fi
		FAILED_PKG="$(echo "$EMERGE_SECOND_HALF" \
			| grep "All ebuilds that could satisfy" \
			| cut -d\" -f2)"
		decho FAILED_PKG=$FAILED_PKG
		for (( i = 0; i < ${#SECOND_HALF[@]}; i++ )); do
			if [[ ${SECOND_HALF[$i]} = $FAILED_PKG ]]; then
				SECOND_HALF[$i]=""
			fi
		done
	done

	# Do the first and second halves separately, because both could contain
	# blockers
	if echo $EMERGE_FIRST_HALF \
		| grep blocks \
		| grep -e virtual/x11 -e virtual/xft -e xorg-x11 -e libXft > /dev/null; then
		find_blocker "${FIRST_HALF[*]}"
	fi

	if echo $EMERGE_SECOND_HALF \
		| grep blocks \
		| grep -e virtual/x11 -e virtual/xft -e xorg-x11 -e libXft > /dev/null; then
		find_blocker "${SECOND_HALF[*]}"
	fi
}

if [[ "$1" = -h ]] || [[ "$1" = --help ]]; then
	usage
fi

if [[ -n "$CATEGORY" ]]; then
	PKGS=$(get_category_packages $PORTDIR $CATEGORY)
else
	PKGS=$(<$PKGFILE)
fi

find_blocker "$PKGS"
