#!/bin/bash

version="1.21"
tanpath="/var/lib/pacman"
tandb="pacsync.db"
errors=0
upgrade=0

message() {
	echo "==> $1" >&2
}

usage() {
	echo "pacsync version $version"
	echo "usage: $0 <operation> [package]"
	echo ""
	echo "operations:"
	echo "  sync               Download a fresh package list from the server"
	echo "  install <pkg>      Download and install <pkg>"
	echo "  upgrade <pkg>      Download and upgrade <pkg>"
	echo "  report             Generate a report of all packages that could be upgraded"
	echo "  sysupgrade         Same as \"report\", but actually do the upgrades"
	echo "  clean              Removes all files from package cache to clear up diskspace"
	echo ""
}

checkdb() {
	if [ ! -f $tanpath/$tandb ]; then
		message "missing package list.  (use \"sync\" first)"
		exit 1
	fi
}

download() {
	targ=$1
	shift
	cl=
	for file in $*; do
		cl="$cl $SYNC_SERVER/$file"
	done
	message "Downloading $targ"
	$ftpagent $cl
	if [ $? -gt 0 ]; then
		message "ERROR: could not download $targ"
		return 1
	fi
	return 0
}

dosync() {
	cd /tmp
	download "package list" pacsync/$tandb
	if [ $? -gt 0 ]; then
		exit 1
	fi
	rm -f $tanpath/$tandb
	mv /tmp/$tandb $tanpath/$tandb
	message "Done."
}

doinstall() {
	pkg2dl=
	pkg2inst=
	for pkgname in $*; do
		line=`egrep "^[a-z]+/$pkgname-[a-zA-Z0-9\.]+-[0-9]+\.pkg\.tar\.gz$" $tanpath/$tandb`
		if [ $? -gt 0 ]; then
			message "package $pkgname not found"
			exit 1
		fi
		pacman=`pacman -Q $pkgname 2>/dev/null`
		if [ $? -eq 0 ]; then
			message "$pkgname is already installed (try using \"upgrade\")"
			exit 1
		fi
		filename=`echo $line | sed 's|^[a-z]*/||g'`
		pkg2inst="$pkg2inst $filename"
		if [ ! -f /var/cache/pacman/pkg/$filename ]; then
			pkg2dl="$pkg2dl $filename"
		fi
	done

	# download packages that aren't already cached
	if [ "$pkg2dl" != "" ]; then
		download "packages" $pkg2dl
		if [ $? -gt 0 ]; then
			exit 1
		fi
		if [ `pwd` != "/var/cache/pacman/pkg" ]; then
			# move downloaded files into cache
			mkdir -p /var/cache/pacman/pkg
			mv $pkg2dl /var/cache/pacman/pkg/
		fi
	fi

	# install packages
	message "Installing packages"
	cd /var/cache/pacman/pkg
	pacman -A $pkg2inst
	if [ $? -gt 0 ]; then
		echo "ERROR: some packages failed to install"
		exit 1
	fi

	message "Done"
	exit 0
}

doupgrade() {
	pkg2dl=
	pkg2up=
	for pkgname in $*; do
		line=`egrep "^[a-z]+/$pkgname-[a-zA-Z0-9\.]+-[0-9]+\.pkg\.tar\.gz$" $tanpath/$tandb`
		if [ $? -gt 0 ]; then
			message "package $pkgname not found"
			exit 1
		fi
		pacman=`pacman -Q $pkgname 2>/dev/null`
		if [ $? -gt 0 ]; then
						message "$pkgname is not installed (use \"install\" first)"
			exit 1
		fi
		pkgver=`echo $pacman | awk '{print $2}'`
		package="$pkgname-$pkgver"
		filename=`echo $line | sed 's|^[a-z]*/||g'`
		# compare filename and package.  if they are at all different, we
		# assume that the newer version is on the server and do the upgrade
		if [ "$filename" = "$package.pkg.tar.gz" ]; then
			message "$pkgname is already up to date (skipping)"
		else
			pkg2up="$pkg2up $filename"
			if [ ! -f /var/cache/pacman/pkg/$filename ]; then
				pkg2dl="$pkg2dl $filename"
			fi
		fi
	done

	# download packages that aren't already cached
	if [ "$pkg2dl" != "" ]; then
		download "packages" $pkg2dl
		if [ $? -gt 0 ]; then
			exit 1
		fi
		if [ `pwd` != "/var/cache/pacman/pkg" ]; then
			# move downloaded files into cache
			mkdir -p /var/cache/pacman/pkg
			mv $pkg2dl /var/cache/pacman/pkg/
		fi
	fi

	# install packages
	if [ "$pkg2up" != "" ]; then
		message "Upgrading packages"
		cd /var/cache/pacman/pkg
		pacman -U $pkg2up
		if [ $? -gt 0 ]; then
			echo "ERROR: some packages failed to upgrade"
			exit 1
		fi
		message "Done"
	fi

	exit 0
}

doreport() {
	headers=0
	pkg2up=
	for pkgfile in `cat $tanpath/$tandb | sed "s|^[a-z]*/||g"`; do
		pkgname=`echo $pkgfile | sed 's|-[a-zA-Z0-9\.]*-[0-9]*\.pkg\.tar\.gz||g'`
		pacman=`pacman -Q $pkgname 2>/dev/null`
		if [ $? -gt 0 ]; then
			# skip this one, it's not installed
			continue
		fi
		pkgver=`echo $pacman | awk '{print $2}'`
		locfile="$pkgname-$pkgver"
		remfile=`echo $pkgfile | sed 's|^[a-zA-Z]*/||g' | sed 's|\.pkg\.tar\.gz||g'`
		# compare locfile and remfile
		if [ "$locfile" = "$remfile" ]; then
			# this package is up to date
			continue
		else
			if [ "$headers" = "0" ]; then
				echo "+--------------------------------------+--------------------------------------+"
				echo "|               LOCAL                  |                 REMOTE               |"
				echo "+--------------------------------------+--------------------------------------+"
				headers=1
			fi
			echo -n "| $locfile"
			awk "BEGIN { for (j=length(\"$locfile\"); j<36; j++) printf \" \" }"
			echo -n " | "
			awk "BEGIN { for (j=length(\"$remfile\"); j<36; j++) printf \" \" }"
			echo "$remfile |"
			pkg2up="$pkg2up $pkgname"
		fi
	done
	if [ "$headers" = "1" ]; then
		echo "+--------------------------------------+--------------------------------------+"
	fi

	# do we upgrade?
	if [ "$upgrade" = "1" -a "$pkg2up" != "" ]; then
		echo ""
		echo -n "Do you want to upgrade these packages? [Y/n] "
		read answer
		echo ""
		if [ "$answer" = "y" -o "$answer" = "Y" -o "$answer" = "" ]; then
			doupgrade $pkg2up
		fi
	fi
	
	exit 0
}

if [ $# -lt 1 ]; then
	usage
	exit 0
fi

if [ -f /etc/pacsync.conf ]; then
	. /etc/pacsync.conf
else
	message "error: missing configuration file!"
	exit 1
fi

proto=`echo $SYNC_SERVER | sed 's|://.*||'`
# check for a download utility
if [ -x /usr/bin/lftpget -a "$proto" = "ftp" ]; then
	ftpagent="/usr/bin/lftpget"
elif [ -x /usr/bin/wget ]; then
	ftpagent="/usr/bin/wget --passive-ftp --tries=3 --waitretry=3"
else
	message "error: you need an ftp client installed (lftp or wget) in /usr/bin"
	exit 1
fi

op=$1
shift
if [ "$1" = "-v" ]; then
	verbose=1
	shift
fi
case $op in
	sync)
		dosync
	;;
	install)
		checkdb
		if [ "$1" = "" ]; then
			message "error: no package specified"
			exit 1
		fi
		doinstall $*
	;;
	upgrade)
		checkdb
		if [ "$1" = "" ]; then
			message "error: no package specified"
			exit 1
		fi
		doupgrade $*
	;;
	report)
		checkdb
		doreport
	;;
	sysupgrade)
		checkdb
		upgrade=1
		doreport
	;;
	clean)
		message "Removing packages from cache"
		rm -f /var/cache/pacman/pkg/*
	;;
	*)
		message "error: invalid operation"
		exit 1
	;;
esac
