Skip to content

Instantly share code, notes, and snippets.

@bergercookie
Created April 22, 2021 11:13
Show Gist options
  • Save bergercookie/638cccb9aa82c036cb71341108fbb8ef to your computer and use it in GitHub Desktop.
Save bergercookie/638cccb9aa82c036cb71341108fbb8ef to your computer and use it in GitHub Desktop.
Version of ppa-purge with a way of skipping updating the packages on every run
#!/bin/bash
# A script to remove all packages in a PPA and revert back to the normal
# distribution ones.
#
# AUTHORS: Robert Hooker (Sarvatt), Tormod Volden
# Defaults
F_ARCHS=$(dpkg --print-foreign-architectures)
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:ppaowner>[/ppaname]"
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 [ppaname] PPA name to be disabled (default: ppa)"
echo " -o [ppaowner] PPA owner"
echo " -s [host] Repository server (default: ppa.launchpad.net)"
echo " -d [distribution] Override the default distribution choice."
echo " -y Pass "-y --force-yes" to apt-get or "-y" to aptitude"
echo " -i Reverse preference of apt-get upon aptitude."
echo " -S Skip updating the mirrors."
echo " -h Display this help text"
echo
echo "Example usage commands:"
echo " sudo ppa-purge -o xorg-edgers"
echo " will remove https://launchpad.net/~xorg-edgers/+archive/ppa"
echo
echo " sudo ppa-purge -o sarvatt -p xorg-testing"
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:o:s:d:ySih\?" opt; do
case "$opt" in
p ) PPANAME="$OPTARG";;
o ) PPAOWNER="$OPTARG";;
s ) PPAHOST="$OPTARG";;
d ) DIST="$OPTARG";;
y ) FORCEINSTALL="true";;
S ) DO_UPDATE="false";;
i ) APTALT="true";;
h ) usage 0;;
\?) usage 1;;
* ) warn "Unknown option '$opt'"; usage 1;;
esac
done
shift $(($OPTIND -1))
if [ -z "$PPAOWNER" ]; then
PPAOWNER=$1
fi
APTARG=""
if [ ! -z "$APTALT" ]; then
if [ ! -z "$FORCEINSTALL" ]; then
APTARG="-y"
fi
APT=aptitude; APTALT=apt-get
else
if [ ! -z "$FORCEINSTALL" ]; then
APTARG="-y --force-yes"
fi
APT=apt-get; APTALT=aptitude
fi
if echo $1 | grep -q "^ppa:"; then
PPAOWNER=$(echo $1 | sed "s#^ppa:\(.*\)/\(.*$\)#\1#")
PPANAME=$(echo $1 | sed "s#^ppa:\(.*\)/\(.*$\)#\2#")
else
if echo $1 | grep -q "^.*/.*$"; then
PPAOWNER=$(echo $1 | sed "s#^\(.*\)/\(.*$\)#\1#")
PPANAME=$(echo $1 | sed "s#^\(.*\)/\(.*$\)#\2#")
fi
fi
if [ -z "$PPAOWNER" ]; then
warn "Required ppa-name argument was not specified"
usage 1
fi
# If not set, using defaults
[ -z "$PPAHOST" ] && PPAHOST="ppa.launchpad.net"
[ -z "$PPANAME" ] && PPANAME="ppa"
[ -z "$DIST" ] && DIST=$(lsb_release -c -s)
if [ "$(id -u)" != "0" ]; then
warn "This script would need superuser privileges, use sudo"
usage 1
fi
if [ -z "$DO_UPDATE" ]; then
msg "Updating packages lists"
if ! $APT update > /dev/null; then
warn "$APT update failed for some reason"
exit 1
fi
else
msg "Skipping update of mirrors"
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
# Get multi-arch package names for revert list
cat $PPA_PKGS | sort -u |
xargs dpkg-query -W -f='${binary:Package}\t${db:Status-Abbrev}\n' 2>/dev/null |
awk '/\tii $/{print $1}' > $REVERTS
# Fallback for Precise
if [ ! -s $REVERTS ]; then
for PACKAGE in $(cat $PPA_PKGS | sort -u); do
dpkg-query -W -f='${PackageSpec}\t${Status}\n' $PACKAGE 2>/dev/null |
awk '/\tinstall/{print $1}' >> $REVERTS
for F_ARCH in $F_ARCHS; do
dpkg-query -W -f='${PackageSpec}\t${Status}\n' "$PACKAGE:$F_ARCH" 2>/dev/null |
awk '/\tinstall/{print $1}' >> $REVERTS
done
done
fi
# Create apt argument list for reverting packages
REINSTALL=""
for PACKAGE in $(cat $REVERTS); do
AVAIL=$(apt-cache policy $PACKAGE | grep -v "$PPAHOST/$PPAOWNER/$PPANAME" | grep -c "500.*$DIST" )
if [ $AVAIL -eq 0 ]; then
REINSTALL="$REINSTALL $PACKAGE-"
else
REINSTALL="$REINSTALL $PACKAGE/$DIST"
fi
done
msg "Package revert list generated:"
msg "$REINSTALL"
echo
# Disable PPA from sources.list files
for LIST in $(find /etc/apt/ -name "*.list" -exec readlink -f '{}' \;); 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 "Updating packages lists"
$APT update > /dev/null || warn "$APT update failed for some reason"
# FIXME:
# Workaround for now in case APT fails because of missing dependencies.
if $APT $APTARG install $REINSTALL; then
msg "PPA purged successfully"
elif $APTALT $APTARG install $REINSTALL; then
msg "PPA purged successfully using $APTALT fallback"
else
warn "Something went wrong, packages may not have been reverted"
exit 1
fi
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment