#! /bin/bash
#
# pkgsync - Automated package synchronization tool
# 2004-2006 Steinar H. Gunderson <sgunderson@bigfoot.com>.
#
# Licensed under the GNU GPL version 2, as publicshed by the FSF;
# see /usr/share/common-licenses/GPL-2 on Debian systems or visit
# www.fsf.org.
#

set -e
set -o noglob
export DEBIAN_FRONTEND=noninteractive
export VERSION=1.16

if [ ! -r /etc/pkgsync/musthave -o \
     ! -r /etc/pkgsync/mayhave -o \
     ! -r /etc/pkgsync/maynothave ]; then
	echo Error: Missing files in /etc/pkgsync. Aborting.
	echo 
	echo Please see /usr/share/doc/pkgsync/README.Debian for information on 
	echo configuring pkgsync.
	
	exit 1
fi

print_help () {
	echo "pkgsync $VERSION"
	echo "Automated package synchronization tool"
	echo ""
	echo "Usage: pkgsync [OPTIONS]"
	echo "Recognized options:"
	echo "  -h, --help           display this help and exit"
	echo "  -k, --keep-unused    don't remove unused packages"
	echo "  -s, --simulate       don't do anything, just print out what would have happened"
	echo "  -d, --dpkg-glob      use dpkg's globbing (default, but deprecated)"
	echo "  -a, --aptitude-glob  use aptitude's globbing (recommended)"
	echo ""
	echo "Complete documentation can be found in /usr/share/doc/pkgsync/README.Debian."
}

# Largely adapted from /usr/lib/getopt/parse.bash
parse_options () {
	TEMP=`getopt -o hksad --long help,keep-unused,simulate,dpkg-glob,aptitude-glob -n 'pkgsync' -- "$@"`
	eval set -- "$TEMP"

	APTITUDE_ARGS="-y -q"
	GLOB_STYLE="dpkg"

	while :; do
		case "$1" in
			-s|--simulate)
				APTITUDE_ARGS="$APTITUDE_ARGS -s"
				shift
				;;
			-k|--keep-unused)
				APTITUDE_ARGS="$APTITUDE_ARGS -o Aptitude::Delete-Unused=false"
				shift
				;;
			-d|--dpkg-glob)
				GLOB_STYLE="dpkg"
				shift
				;;
			-a|--aptitude-glob)
				GLOB_STYLE="aptitude"
				shift
				;;
			-h|--help)
				print_help
				exit 0
				;;
			--)
				shift
				break
				;;
			*)
				echo "Internal error: doesn't recognize argument '$1'"
				exit 1
				;;
		esac
	done
}
readpkgs () {
	grep -vE '^#' "$1" | grep -vE '^\s*$' || true
}
getpkgs () {
	IFS="
"
	for pkg in $( readpkgs $1 ); do
		# if the line starts with "debtags:", it's a debtags expression,
		# so run it through debtags.
		if echo "$pkg" | grep -Eq '^debtags:'; then
			if ! [ "$USE_DEBTAGS" ]; then
				echo Error: "debtags:" line encountered, but debtags is not installed. Stopping.
				exit 1
			fi
			PATTERN=$( echo "$pkg" | cut -d: -f2- )
			debtags grep "$PATTERN" | tagcoll copy | cut -d: -f1
		else
			# if the line is "meta:current-kernel", use the kernel package
			# for the currently running kernel, if it exists
			if [ "$pkg" = "meta:current-kernel" ]; then
				KVERS=$( uname -r )
				if [ "$GLOB_STYLE" = "dpkg" ]; then
					dpkg-query --showformat '${Package}\n' -W "*-image-$KVERS" 2>/dev/null || true
				else
					aptitude -F '%p' search ".*-image-$KVERS" | sed "s/ \+$//" 2>/dev/null || true
				fi
			else
				# if there's a wildcard in this, push it through dpkg/aptitude
				# to glob. if not, just print it out.
				if [ "$GLOB_STYLE" = "dpkg" ]; then
					if echo "$pkg" | grep -Eq '[][*?]'; then
						dpkg-query --showformat '${Package}\n' -W "$pkg" 2>/dev/null || true
					else
						echo "$pkg"
					fi
				else
					if echo "$pkg" | grep -Eq '[][*?()|~]'; then
						aptitude -F '%p' search "$pkg" | sed "s/ \+$//" 2>/dev/null || true
					else
						echo "$pkg"
					fi
				fi
			fi
		fi
	done
}
run_aptitude () {
	echo RUNNING: aptitude $APTITUDE_ARGS "$@"
	aptitude $APTITUDE_ARGS "$@" 
}
run_debtags () {
	if [ "$USE_DEBTAGS" ]; then
		echo RUNNING: debtags "$@"
		debtags "$@" 
	fi
}

# The beautiful look of hacks in the morning...
filter () { 
	echo "$@" | tr " " "\n" | sort | uniq -c | grep "     2" | cut -c9-
}

parse_options "$@"

# Check if we've got debtags installed
[ -x /usr/bin/debtags ] && USE_DEBTAGS=yes

# Update the package lists
apt-get update
run_debtags update

# Find out what parameters to give to aptitude.
installed=$( dpkg -l | grep '^ii' | cut -c5- | cut '-d ' -f1 )
musthave_install=$( getpkgs /etc/pkgsync/musthave | sort -u | sed "s/$/+/" )
maynothave_remove=$( getpkgs /etc/pkgsync/maynothave | sort -u | sed "s/$/-/" )
mayhave_marknonauto=$( getpkgs /etc/pkgsync/mayhave | sort -u | sed "s/$/\&m/" )
mustormayhave=$( ( getpkgs /etc/pkgsync/musthave ; getpkgs /etc/pkgsync/mayhave ) | sort -u )
rest_markauto=$( filter $installed $installed $mustormayhave | sed "s/$/\&M/" )

run_aptitude dist-upgrade $musthave_install $maynothave_remove $mayhave_marknonauto $rest_markauto
run_aptitude autoclean
