#!/bin/bash -e
#
#   abs - download a PKGBUILD tree from a CVS repository
#
#   Copyright (C) 2002-2007 Judd Vinet <jvinet@zeroflux.org>
#   Copyright (C) 2007-2010 Aaron Griffin <aaron@archlinux.org>
#
#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the GNU General Public License as published by
#   the Free Software Foundation; either version 2 of the License, or
#   (at your option) any later version.
#
#   This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
#

##
# Constants
##
ABS_VERSION="%%ABS_VERSION%%"
CONFDIR="%%CONF_DIR%%"
SYNCCMD='rsync'
SYNCARGS='-mrtv --no-motd --delete-after --no-p --no-o --no-g'
BUG_REPORT_EMAIL=pacman-dev@archlinux.org

##
# Script Exit Reasons
# -------------------
#              E_OK : Everything worked :)
# E_MISSING_PROGRAM : A program the script depends on is not installed.
#    E_CONFIG_ERROR : Missing/incorrect configuration.
#  E_INVALID_OPTION : User has passed unknown/invalid option to script.
##
_E_OK=0
_E_MISSING_PROGRAM=1
_E_CONFIG_ERROR=2
_E_INVALID_OPTION=3

##
# Consistent messaging format
##
msg() {
	local mesg=$1; shift
	printf "==> ${mesg}\n" "$@"
}

error() {
	local mesg=$1; shift
	printf  "==> ERROR: ${mesg}\n" "$@" >&2
}

##
# Source configuration
##
if [ -f "$CONFDIR/abs.conf" ]; then
	source "$CONFDIR/abs.conf"
else
	error "Could not find configuration file $CONFDIR/abs.conf"
	exit $_E_CONFIG_ERROR
fi

##
# User based overrides
##
[ -f ~/.abs.conf ] && source ~/.abs.conf

##
# Helper functions
##
usage() {
	echo "Arch Build System $ABS_VERSION -- synchronization utility"
	echo ""
	echo "Usage:"
	echo "$0 [options] [repository1[/package1] [repository2[/package2] ...]]"
	echo
	echo "Options:"
	echo "  -h, --help     Display this help message then exit."
	echo "  -V, --version  Display version information then exit."
	echo "  -t, --tarball  Sync ABS tree using tarballs from your pacman mirror."
	echo
	echo "abs will synchronize PKGBUILD scripts from the Arch Linux repositories"
	echo "into $ABSROOT via rsync. If no argument is given, abs will synchronize"
	echo "the repositories specified in ${CONFDIR}abs.conf."
	echo
	echo "Report bugs to $BUG_REPORT_EMAIL with [ABS] in the subject"
}

version() {
	echo "abs $ABS_VERSION"
	echo
	echo "Copyright (C) 2002-2007 Judd Vinet <jvinet@zeroflux.org>"
	echo "Copyright (C) 2007-2010 Aaron Griffin <aaron@archlinux.org>"
	echo
	echo "This is free software; see the source for copying conditions."
	echo "There is NO WARRANTY, to the extent permitted by law."
}

update_rsync() {
	cd "$ABSROOT"

	if [ ! "$(type -p rsync)" ]; then
		error "missing rsync synchronization utility.  Install rsync."
		exit $_E_MISSING_PROGRAM
	fi

	if [ "$CLPARAM" = "" ]; then
		# using repos specified in abs.conf
		for repo in "${REPOS[@]}"; do
			if [ "$repo" != "${repo#!}" ]; then
				EXCLUDE="${EXCLUDE} --filter=-_/${repo#!}/"
			fi
		done

		EXCLUDE="${EXCLUDE} --filter=P_/local/ --filter=P_/README"
		SYNCARGS="${SYNCARGS} --delete-excluded"
	else
		# using repos/packages specified on the command line
		for param in "${REPOS[@]}"; do
			INCLUDE="${INCLUDE} --include=/${param}"
			if [ "$param" != "${param/\/}" ]; then
				repo=${param%/*}
				INCLUDE="${INCLUDE} --include=/${repo}"
				EXCLUDE="${EXCLUDE} --exclude=/${repo}/*"
				
				# temporary while community repo still has package categories 
				# fixes FS#11582
				if [ "$repo" != "${repo/\/}" ]; then
					repo=${repo%/*}
					INCLUDE="${INCLUDE} --include=/${repo}"
					EXCLUDE="${EXCLUDE} --exclude=/${repo}/*"
				fi
			fi
		done

		# remove duplicate values
		INCLUDE=$(echo $INCLUDE | tr " " "\n" | sort -u | tr "\n" " ")
		EXCLUDE="${EXCLUDE} --exclude=/*"
	fi

	msg "Starting ABS sync..."
	$SYNCCMD $SYNCARGS $INCLUDE $EXCLUDE ${SYNCSERVER}::abs/{${ARCH},any}/ $ABSROOT
}

update_tarball() {
	cd "$ABSROOT"

	if [ ! "$(type -p wget)" ]; then
		error "missing wget download utility.  Install wget."
		exit $_E_MISSING_PROGRAM
	fi

	if [ -f "$MIRRORLIST" ]; then
		mirrorlist=$(grep "^Server" $MIRRORLIST | cut -f3 -d" ")
	else
		error "Could not find pacman mirrorlist file $MIRRORLIST"
		exit $_E_CONFIG_ERROR
	fi

	msg "Downloading tarballs..."
	for repo in "${REPOS[@]}"; do
		if [ "$repo" == "${repo#!}" ]; then
			echo "    ==> ${repo}..."

			ret=0
			for mirror in ${mirrorlist[@]}; do
				tarball=$(echo $mirror | sed "s#\$repo#$repo#;s#\$arch#$ARCH#")
				tarball="${tarball}/${repo}.abs.tar.gz"
				protocol=$(echo $tarball | cut -f1 -d":")
				if [ "$protocol" == "file" ]; then
					tarball=$(echo $tarball | sed "s#file://##")
					ln -s $tarball . 2>/dev/null || ret=$?
					if [ $ret -ne 0 ]; then
						ret=0
					fi
				else
					wget -q $tarball || ret=$?
				fi
				if [ $ret -eq 0 ]; then
					break
				fi
			done

			if [ $ret -ne 0 ]; then
				error "Download failed"
				continue
			fi

			rm -rf $repo
			tar -xzf ${repo}.abs.tar.gz
			rm ${repo}.abs.tar.gz
		fi
	done
}

##
# Signal Traps
##
trap 'error "TERM signal caught. Exiting..."; exit 1' TERM HUP QUIT
trap 'error "Aborted by user! Exiting..."; exit 1' INT
trap 'error "An unknown error has occured. Exiting..."; exit 1' ERR

##
# Parse Options
##
OPT_SHORT="hVt"
OPT_LONG="help,version,tarball"
OPT_TEMP="$(getopt -o "$OPT_SHORT" -l "$OPT_LONG" -n "$(basename "$0")" -- "$@" || echo 'GETOPT GO BANG!')"
if echo "$OPT_TEMP" | grep -q 'GETOPT GO BANG!'; then
	# This is a small hack to stop the script bailing with 'set -e'
	echo; usage; exit $_E_INVALID_OPTION;
fi
eval set -- "$OPT_TEMP"
unset OPT_SHORT OPT_LONG OPT_TEMP

while true; do
	case "$1" in
		-h|--help)     usage; exit $_E_OK;;
		-V|--version)  version; exit $_E_OK;;
		-t|--tarball)  TARBALL=1;;

		--)            OPT_IND=0; shift; break;;
		*)             usage; exit $_E_INVALID_OPTION;; 
	esac
	shift
done

if [ "$#" -gt "0" ]; then
	CLPARAM=1
	REPOS=("$@")
fi

## 
# Verify Config
##
if [ ! -d "$ABSROOT" ]; then
	error "$ABSROOT does not exist (or is not a directory)"
	exit $_E_CONFIG_ERROR
fi

if [ ! -w "$ABSROOT" ]; then
	error "no write permissions in $ABSROOT"
	exit $_E_CONFIG_ERROR 
fi

##
# Go-go Update ABS tree!
##

# Use tarball method on first run
[ "$(ls -A $ABSROOT | sed -e 's#local##' -e 's#README##')" ] || TARBALL=1

if [ "$TARBALL" ]; then
	update_tarball
else
	update_rsync
fi

exit $_E_OK

# vim: set ts=2 sw=2 noet:
