#!/bin/sh
# A script to remove all packages in a PPA and revert back to the normal
# distribution ones.
#
# AUTHORS: Robert Hooker (Sarvatt), Tormod Volden
#
# History:
# v0.1   - 2009-07-28: Initial Revision.
# v0.2   - 2009-07-29: Add warnings, do not remove ppa-purge package
# v0.2.2 - 2009-08-05: Fix command option parsing errors
# v0.2.3 - 2009-08-06: Removed verbose option. Also minor fixups
# v0.2.4 - 2009-08-13: Package dependencies
# v0.2.5 - 2009-09-30: New command syntax, various code rewrites
# v0.2.6 - 2009-12-05: No change version bump to fix packaging problems.

# Defaults
PPAHOST=ppa.launchpad.net
PPANAME=ppa

DIST=$(lsb_release -c -s)
ARCH=$(dpkg --print-architecture)
PPA_PKGS=$(mktemp)
REVERTS=$(mktemp)
trap "rm $PPA_PKGS $REVERTS" 0

# Functions to write output nicely.
write_msg() {
    echo "$*" | fold -s -w "${COLUMNS:-80}"
}

msg() {
	write_msg "$*"
}

warn() {
	write_msg "Warning:  $*" 1>&2
}

usage() {
	echo "Usage: sudo ppa-purge [options] <ppa-name>"
	echo
	echo "ppa-purge will reset all packages from a PPA to the standard"
	echo "versions released for your distribution."
	echo
	echo "Options:"
	echo "	-p [ppa]	Name of the PPA to be reset (default: ppa)"
	echo "	-s [host]	Repository server (default: ppa.launchpad.net)"
	echo "	-h      	Display this help text"
	echo
	echo "Example usage commands:"
	echo "	  sudo ppa-purge xorg-edgers"
	echo "	will remove https://launchpad.net/~xorg-edgers/+archive/ppa"
	echo
	echo "	  sudo ppa-purge -p xorg-testing sarvatt"
	echo "	will remove https://launchpad.net/~sarvatt/+archive/xorg-testing"
	echo
	echo "	  sudo ppa-purge ppa:ubuntu-x-swat/x-updates"
	echo "	will remove https://launchpad.net/~ubuntu-x-swat/+archive/x-updates"
	echo
	echo "Notice: If ppa-purge fails for some reason and you wish to try again,"
	echo "(For example: you left synaptic open while attempting to run it) simply"
	echo "uncomment the PPA from your sources, run apt-get update and try again."
	echo
	exit $1
}

# Command line options
while getopts "p:s:h\?" opt; do
	case "$opt" in
		p ) PPANAME="$OPTARG"				;;
		s ) PPAHOST="$OPTARG"				;;
		h ) usage 0;					;;
		\?) usage 1;					;;
		* ) warn "Unknown option '$opt'"; usage 1;	;;
	esac
done
shift $(($OPTIND -1))

PPAOWNER=$1

if echo $1 | grep -q "^ppa:"; then
	PPAOWNER=$(echo $1 | sed "s#^ppa:\(.*\)/\(.*$\)#\1#")
	PPANAME=$(echo $1 | sed "s#^ppa:\(.*\)/\(.*$\)#\2#")
fi

if [ -z "$PPAOWNER" ]; then
	warn "Required ppa-name argument was not specified"
	usage 1
fi

if [ "$(id -u)" != "0" ]; then
	warn "This script would need superuser privileges, use sudo"
fi

msg "PPA to be removed: $PPAOWNER $PPANAME"

# Make list of all packages in PPA
PPA_LIST=/var/lib/apt/lists/${PPAHOST}_${PPAOWNER}_${PPANAME}_*_Packages
for LIST in $PPA_LIST; do
	if [ -e $LIST ]; then
		grep "^Package: " $LIST | cut -d " " -f2 | sort >> $PPA_PKGS
	fi
done

if [ ! -s $PPA_PKGS ]; then
	warn "Could not find package list for PPA: $PPAOWNER $PPANAME"
	exit 1
fi

# Ignore the ppa-purge package
if grep -q "ppa-purge" $PPA_PKGS; then
	sed -i '/ppa-purge/d' $PPA_PKGS
	msg "Note: Not removing ppa-purge package"
fi

dpkg --get-selections | awk '/install$/{print $1}' |
     sort | comm -12 - $PPA_PKGS > $REVERTS

# Create apt-get argument list for reverting packages
REINSTALL=""
for PACKAGE in $(cat $REVERTS); do
	REINSTALL="$REINSTALL $PACKAGE/$DIST"
done

msg "Package revert list generated:"
msg "$REINSTALL"
echo

# Disable PPA from sources.list files
for LIST in /etc/apt/sources.list /etc/apt/sources.list.d/*.list; do
	if [ -e $LIST ] && grep -q $PPAOWNER/$PPANAME $LIST; then
		msg "Disabling $PPAOWNER PPA from $LIST"
		sed -ri "\:^[^#]+/${PPAOWNER}/${PPANAME}/:s/^deb/# deb/" $LIST
	fi
done

msg "Running apt-get update"
apt-get update > /dev/null || warn "apt-get update failed for some reason"

# FIXME:
# Workaround for now in case apt-get fails because of a package not in Ubuntu.
# Aptitude actually works but it would be preferred to remove the package
# from $REINSTALL directly.

if apt-get install $REINSTALL; then
	msg "PPA purged successfully"
elif aptitude install $REINSTALL; then
	msg "PPA purged successfully using aptitude fallback"
else
	warn "Something went wrong, packages may not have been reverted"
	exit 1
fi
exit 0
