#!/bin/bash
# upkg-remove
#
# uninstall a package but save user modified files
#
# Copyright (C) 2004-2007 Raffaele Sandrini, Jürg Billeter
#
# This file is part of Upkg (http://www.upkg.org).
#
# Upkg is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2
# as published by the Free Software Foundation.
#
# Upkg 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 Upkg; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Authors:
#   Raffaele Sandrini <rasa at paldo dot org>
#   Jürg Billeter <juerg at paldo dot org>

# this script passes execution to upkg for high-level package removal
# so first check whether a low-level argument has been given

lowlevel=0

for i in $*
do
	case $i in
		--force|--pre-upgrade|--post-upgrade)
			lowlevel=1
			break
			;;
	esac
done

if [ $lowlevel -eq 0 ]
then
	echo "Generating script..."
	upkg --remove --disable-source "$@" script || { echo "Could not generate script!" ; exit 1 ; }

	echo "Executing script..."
	bash /var/cache/upkg/script
	exit $?
fi

# argument parsing
set -- $(POSIXLY_CORRECT=1 getopt -u -l force,pre-upgrade,post-upgrade,verbose "" $*)

function exec_log ()
{
	if [ $verbose -eq 0 ]
	then
		$@ > /dev/null 2>&1
	else
		$@
	fi
}

function upkgcat ()
{
	for f in "$@"; do
		if [ -e "$f.zst" ]; then
			zstdcat "$f.zst"
		elif [ -e "$f.xz" ]; then
			xzcat "$f.xz"
		elif [ -e "$f.bz2" ]; then
			bzcat "$f.bz2"
		elif [ -e "$f.gz" ]; then
			zcat "$f.gz"
		elif [ -e "$f" ]; then
			cat "$f"
		fi
	done
}

verbose=0
mode=0 # mode 0: normal remove, mode 1: pre-upgrade, mode 2: post-upgrade

for i in $* ; do
	case $i in
		--force) shift;;
		--pre-upgrade) mode=1; shift;;
		--post-upgrade) mode=2; shift;;
		--verbose) verbose=1; shift;;
		--) shift; break;;
	esac
done

if [ "$1" = "" ] ; then
	echo "Usage: $0 [--force|--pre-upgrade|--post-upgrade] PACKAGE"
	exit 1
fi

[ -L /var/lib/upkg/packages/$1 ] || { echo "ERROR: Package $1 not found." ; exit 1 ; }

if [ "$mode" = "0" -o "$mode" = "1" ] ; then
	FULLNAME=$(readlink /var/lib/upkg/packages/$1)
elif [ "$mode" = "2" ] ; then
	FULLNAME=$(readlink /var/lib/upkg/packages/$1.saved)
	NEWFULLNAME=$(readlink /var/lib/upkg/packages/$1)
fi

if [ "$mode" = "0" ]
then
	message="Removing $FULLNAME..."
	echo $message
	date +"%F %T $message" >> /var/log/upkg/upkg.log
fi

if [ "$mode" = "0" -o "$mode" = "1" ] ; then
	[ -e /var/lib/upkg/scripts/$FULLNAME.prerm ] && exec_log bash /var/lib/upkg/scripts/$FULLNAME.prerm

	BACKUP=0
	upkgcat /var/lib/upkg/files/$FULLNAME.digest | (
		while read md5sum file ; do
			if [ -L "$file" ] || [[ "$file" =~ ^(/bin/|/lib/|/sbin/|/usr/) ]]
			then
				[ "$mode" = "0" ] && rm -f "$file"
				continue
			fi
			md5sum --text "$file" 2>/dev/null | (
				while read md5sum2 file2 ; do
					if [ $md5sum == $md5sum2 ] ; then
						[ "$mode" = "0" ] && rm -f "$file"
					else
						if [ $BACKUP -eq 0 ] ; then
							BACKUP=1
							echo "The following files have been modified since package installation, they will be renamed:" >&2
						fi
						if [ "$mode" = "0" ] ; then
							mv "$file"{,.saved}
						else
							cp -a "$file"{,.saved}
						fi
						echo "$md5sum  $file2" >> /var/lib/upkg/files/$1.saved
						echo " - $file ==> $file.saved" >&2
					fi
				done
			)
		done
	)
	if [ "$mode" = "0" ] ; then
		upkgcat /var/lib/upkg/files/$FULLNAME.links 2>/dev/null | (
			while read target link ; do
				rm -f $link
			done
		)
	fi
else
	# remove the file if the new version doesn't need it anymore
	upkgcat /var/lib/upkg/files/$FULLNAME.{digest,links} | sed -e 's/  / /' | cut -d ' ' -f 2 | sort -u > /tmp/upkg-old.files
	upkgcat /var/lib/upkg/files/$NEWFULLNAME.{digest,links} | sed -e 's/  / /' | cut -d ' ' -f 2 | sort -u > /tmp/upkg-new.files
	diff /tmp/upkg-{old,new}.files | grep \< | cut -b 3- | (
		while read file ; do
			# keep the file if it is newer than the old package
			# => prevents deleting files moved from one package to an other package
			[ "$file" -nt /var/lib/upkg/packages/$FULLNAME ] || rm -f "$file"
		done
	)
	rm -f /tmp/upkg-{old,new}.files
fi

if [ "$mode" = "0" ] ; then
	# use while-loop instead of xargs to ensure the reverse order
	upkgcat /var/lib/upkg/files/$FULLNAME.dirs | tac | (
		while read dir ; do
			exec_log rmdir --ignore-fail-on-non-empty $dir
		done
	)
elif [ "$mode" = "2" ] ; then
	# remove the directory if the new version doesn't need it anymore
	upkgcat /var/lib/upkg/files/$FULLNAME.dirs 2>/dev/null | tac > /tmp/upkg-old.dirs
	upkgcat /var/lib/upkg/files/$NEWFULLNAME.dirs 2>/dev/null | tac > /tmp/upkg-new.dirs
	# use while-loop instead of xargs to ensure the reverse order
	diff /tmp/upkg-{old,new}.dirs | grep \< | cut -b 3- | (
		while read dir ; do
			exec_log rmdir --ignore-fail-on-non-empty
		done
	)
	rm -f /tmp/upkg-{old,new}.dirs
fi

if [ "$mode" = "0" -o "$mode" = "2" ] ; then
	rm -f /var/lib/upkg/files/$FULLNAME.{digest,links,dirs,config}.{gz,bz2,xz,zst}
	rm -f /var/lib/upkg/logs/$FULLNAME.log.{gz,bz2,xz,zst}
	rm -f /var/lib/upkg/scripts/$FULLNAME.prerm
	rm -f /var/lib/upkg/packages/$FULLNAME
	rm -f /var/lib/upkg/packages/$FULLNAME.info
fi

if [ "$mode" = "0" ] ; then
	rm -f /var/lib/upkg/packages/$1
	rm -f /var/lib/upkg/packages/$1.{keep,select}
elif [ "$mode" = "1" ] ; then
	mv /var/lib/upkg/packages/$1{,.saved}
elif [ "$mode" = "2" ] ; then
	# Package upgrading: process files which have been saved during the removal of the old package
	cat /var/lib/upkg/files/$1.saved 2>/dev/null | (
		while read md5sum file ; do
			[ -f "$file".saved ] || continue # continue only if the saved file still exists
			# if package upgrade hasn't modified file ==> restore user changes
			( echo \"$md5sum  $file\" | md5sum -c --status ) && mv "$file"{.saved,}
		done
	)
	rm -f /var/lib/upkg/files/$1.saved
	rm -f /var/lib/upkg/packages/$1.saved
fi

