#!/bin/sh
#
# Copyright (c) 2006 Dominic Fandrey <lon_kamikaze@gmx.de>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#

version=1.2

# Use the script call as a command given to the selected startscript.
# Several commands can be realized with symlinks to this script,
# such as fetch, configure, package and so on. All with the prefix 'port'.
command=$(echo $0 | sed -E 's|^.*/port||1')

# Global options.
portupgrade_parameters="-n"
option_verbose="2>&1"
option_retries=0
# This prevents running portupgrade when no ports were named.
run_portupgrade=0

# Display help.
config_help() {
	echo "portconfig ($command) v$version
usage:	port$command [-v] [-a] [-f] [-r] [-R] [-h] [-tN] [ports]"
}

# Handle parameters.
config_options() {
	case $1 in
		"-v" | "--verbose") {
			option_verbose=
			return 0
		};;
		"-a" | "--all") {
			run_portupgrade=1
			portupgrade_parameters="-a $portupgrade_parameters"
			return 0
		};;
		"-f" | "--force") {
			portupgrade_parameters="-fN $portupgrade_parameters"
			return 0
		};;
		"-r" | "--recursive") {
			portupgrade_parameters="-r $portupgrade_parameters"
			return 0
		};;
		"-R" | "--upward-recursive") {
			portupgrade_parameters="-R $portupgrade_parameters"
			return 0
		};;
		-t[0-9] | --try-again[0-9]) {
			option_retries=$(echo $1 | sed 's|[^0-9]*||g')
			return 0
		};;
		"-h" | "--help") {
			config_help
			return 0
		};;
		-? | --*) {
			echo "Unknown parameter \"$1\""
			return 0
		};;
		-*) {
			# Split parameters.
			parameter_tail=$(echo $1 | sed -E 's|^[-].||1')
			parameter=$(echo $1 | sed -E "s|$parameter_tail\$||1")
			# Handle the first parameter.
			config_options $parameter
			# Handle the following parameters.
			config_options -$parameter_tail
			return 0
		};;
		*) {
			# Add to the list of ports that should be processed.
			run_portupgrade=1
			portupgrade_parameters="$portupgrade_parameters $1"
			return 0
		};;
	esac

	# The given parameter is not an option.
	return 1
}

for parameter; {
	config_options $parameter
}

# Determine portsdir
portsdir=$(make -V PORTSDIR -f /usr/share/mk/bsd.port.mk)
if [ ! -d $portsdir ]; then
	echo "The PORTSDIR '$portsdir' is missing."A
	exit 1
fi

# Get the ports to proceed.
if [ $run_portupgrade -eq 1 ]; then
	# Get portupgrade output.
	portupgrade=$(eval "portupgrade $portupgrade_parameters $option_verbose")
	if [ $? -ne 0 ]; then
		echo "Portupgrade failed with the following output:"
		echo "$portupgrade"
	fi

	# Get ports that require updating.
	upgrade=$(echo "$portupgrade" | grep -E "[[:space:]]\+ " | sed -E 's|[[:space:]]\+ ||1' | sed -E 's| (.+)$||1')

	# Get ports that have to be installed.
	install=$(echo "$portupgrade" | grep -E "^Install" | sed -E 's|^Install ||1' | sed -E 's|\?.*$||1' | sed "s|'||g")

	# Merge upgrade and install list.
	ports=$(echo -e "$upgrade\n$install" | grep -Ev '^$')

	if [ "$option_verbose" = "" ]; then
		echo "The following ports will be affected:"
		echo "$ports"
	fi
fi

# Collect failed ports here.
failed_ports=

# Run command for all selected ports.
for port in $ports; {
	if [ "$option_verbose" = "" ]; then
		echo "Make '$command' for '$port'"
	fi

	# Run the command until the given number of tries is reached.
	for count in 0 1 2 3 4 5 6 7 8 9; {
		# Run the make target.
		eval "cd $portsdir/$port && make $command"
		
		# The command succeeded. No need to retry.
		if [ $? -eq 0 ]; then
			break
		fi

		# There are more tries left.
		if [ $count -ne $option_retries ]; then
			continue
		fi

		# The command failed on the last try. Count your losses.
		failed_ports="$failed_ports $port"
		break
	}
}

# Inform the user of ports which did not return 0.
if [ "$failed_ports" != "" ]; then
	echo "The following ports failed: $failed_ports"
fi
