#!/bin/sh -efu
#
# Copyright (C) 2006-2007  Alexey Tourbin <at@altlinux.org>
# Copyright (C) 2006       Dmitry V. Levin <ldv@altlinux.org>
#
# Optimizes package list by excluding dependent packages.
#
# 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; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#

PROG="${0##*/}"

exit_handler()
{
	local rc=$?
	trap - EXIT
	rm -rf -- "$workdir"
	exit $rc
}

workdir="$(mktemp -dt "$PROG.XXXXXXXXXX")"
trap exit_handler EXIT HUP INT QUIT PIPE TERM

cd "$workdir"
export LC_COLLATE=C

# make list of package names
if [ $# -gt 0 ]; then
	printf %s "$*" |xargs -n1 printf '%s\n'
else
	xargs -n1 printf '%s\n'
fi >n
sort -u -o n n

# make list of requirements
xargs -r rpmquery --qf '[%{REQUIRENAME}\t%{NAME}\n]' -- <n >Rn
sort -k1,1 -k2,2 -u -o Rn Rn

# make list of provides
xargs -r rpmquery --qf '[%{PROVIDENAME}\t%{NAME}\n][%{FILENAMES}\t%{NAME}\n]' -- <n >Pn
sort -k1,1 -k2,2 -u -o Pn Pn

# make relation Requires(pkg1->dep->pkg2)
join -j 1 -o '1.2 0 2.2' Rn Pn |sort -u -k1,1 -k2,2 -k3,3 >nRn

# Check if the same virtual dep resolves to different packages, e.g.
#	rpm-build	autoconf	autoconf_2.50
#	rpm-build	autoconf	autoconf_2.60
awk '{print$3,$2}' <nRn |sort -u -k2,2 -k1,1 |uniq -D -f1 |cut -d' ' -f2 >R-amb
if [ -s R-amb ]; then
	sort -u -o R-amb R-amb
	sort -k2,2 <nRn |join -12 -21 -o '1.1 1.2 1.3' - R-amb >nRn-amb
	echo "$PROG: ambiguous virtual dependencies:"
	sed -e 's/ / -> /g' <nRn-amb
fi >&2

# Assist loop breaks.  Consider this:
#	gcc-common	/usr/bin/i586-alt-linux-gcc	gcc4.1
#	gcc4.1		gcc-common			gcc-common
# We would like gcc4.1 to take precedence, because gcc4.1 explicitly
# requires gcc-common.
awk '$2==$3{print$1,$3}' <nRn |sort -u >nn-real
awk '$2!=$3{print$1,$3}' <nRn |sort -u >nn-virt
comm -23 nn-virt nn-real >nn-virt-only
mv -f nn-virt-only nn-virt
# nn-real:	gcc4.1		gcc-common
# nn-virt:	gcc-common	gcc4.1
awk '{print$2,$1}' <nn-virt |sort -u >reverse-nn-virt
comm -12 reverse-nn-virt nn-real >nn-real-virt-loop
if [ -s nn-real-virt-loop ]; then
	echo "$PROG: simple RV-loop (first package takes precedence):"
	sed -e 's/ / <-> /g' <nn-real-virt-loop
	awk '{print$2,$1}' <nn-real-virt-loop |sort -u >nn-virt-bad
	comm -23 nn-virt nn-virt-bad >nn-virt-good
	mv -f nn-virt-good nn-virt
fi >&2

# make list of package pairs where first depends on second
sort -u nn-real nn-virt >nn

# tsort this list of pairs
tsort <nn >t || [ -s t ]

# make list of package names which satisfy other package requirements
awk <nn >s '
BEGIN {
	N=0
	while ((getline <"t") > 0)
		t[++N] = $1
}
{
	nn[$1,$2] = 1
}
END {
	for (i = 1; i < N; i++) {
		d = t[i]
		for (j = i+1; j <= N; j++) {
			s = t[j]
			if (nn[d,s])
				print s
		}
	}
}'
sort -u -o s s

# substract names of packages-satisfiers from the whole list
comm -23 n s
