#!/bin/sh
# --- T2-COPYRIGHT-NOTE-BEGIN ---
# This copyright note is auto-generated by ./scripts/Create-CopyPatch.
# 
# T2 SDE: misc/archive/compare.sh
# Copyright (C) 2004 - 2005 The T2 SDE Project
# 
# More information can be found in the files COPYING and README.
# 
# 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; version 2 of the License. A copy of the
# GNU General Public License can be found in the file COPYING.
# --- T2-COPYRIGHT-NOTE-END ---

verbose=0
quiet=0

ignspace=0
ignprio=0
ignrepo=0
dopatch=0

source=
targets=
repositories=
packages=

function show_usage() {
	echo "usage: $0 [-q[q]] [-v] [-r] {action}"
	echo
	echo "action: [-p [-P] [-S]] <source> <target> [-repository <repo>|<packages>|]"
	echo "        -3 <source> <target1> <target2> [-repository <repo>|<packages>|]"
	echo
	echo "    -q: don't show packages with the same version"
	echo "   -qq: don't show packages missing or with the same version"
	echo "    -v: show extra info about the packages"
	echo "    -r: don't show repository name"
	echo
	echo "    -p: show patch to turn \$source into \$target"
	echo "    -P: ignore [P]s of .desc files on patches"
	echo "    -S: ignore spaces on patches" 
}

# TODO: it would be great to port it to "-n <n>" instead of -3
#
while [ $# -gt 0 ]; do
	case "$1" in
		-v)	verbose=1	;;
		-r)	ignrepo=1	;;
		-q)	quiet=1		;;
		-qq)	quiet=2		;;
		-p)	dopatch=1	;;
		-P)	ignprio=1	;;
		-S)	ignspace=1	;;

		-3)	source="$2"
			targets="$3 $4"
			shift 3		;;

		-repository) 
			shift
			repositories="$*"; set -- 
			;;
		*)	if [ "$targets" ]; then
				packages="$*"; set --
			elif [ "$source" ]; then
				targets="$1"
			else
				source="$1"
			fi
	esac
	shift
done
			
function remove_header() {
	# thanks you blindcoder :)
	#
	local here=0 count=1
	while read line ; do
		count=$(( ${count} + 1 )) 
		[ "${line//COPYRIGHT-NOTE-END/}" != "${line}" ] && here=${count}
	done < $1
	tail -n +${here} $1
}
function show_nice_diff() {
	local diffopt=
	[ $ignspace -eq 1 ] && diffopt='-EBb'

	diff -u $diffopt "$1" "$2" | sed \
		-e 's,^--- .*,--- old/package/'"${3##*/package/}," \
		-e 's,^[\+][\+][\+] .*,+++ new/package/'"${3##*/package/},"
}

function diff_package() {
	local source="$1"
	local target="$2"
	local x= y=

	# files on source
	for x in $source/*; do
		if [ -d "$x/" ]; then
			diff_package $x $target/${x##*/}
		elif [[ "$x" = *.cache ]]; then
			continue
		elif [ -f "$x" ]; then
			remove_header $x > $$.source
			if [ -f $target/${x##*/} ]; then
				remove_header $target/${x##*/} > $$.target

				if [[ "$x" = *.desc ]]; then
					y=$( grep -e "^\[P\]" $x )
					[ "$y" -a $ignprio -eq 1 ] && sed -i -e "s,^\[P\] .*,$y," $$.target
				fi

				show_nice_diff $$.source $$.target $x
				rm $$.target
			else
				show_nice_diff $$.source /dev/null $x
			fi
			rm $$.source
		fi
	done
	# files only on target
	for x in $target/*; do
		if [ -d $x/ ]; then
			[ ! -d $source/${x#$target/} ] && diff_package $source/${x#$target/} $x
		elif [[ "$x" = *.cache ]]; then
			continue
		elif [ -f "$x" ]; then
			if [ ! -f "$source/${x#$target/}" ]; then
				remove_header $x > $$.target
				show_nice_diff /dev/null $$.target $source/${x#$target/}
				rm $$.target
			fi
		fi
	done
}

# grabdata confdir field
function grabdata() {
	local confdir=$1
	local pkg=$2
	local field=$3
	local output=

	case "$field" in
		version)	output=$( grabdata_desc $confdir/$pkg.desc $field ) ;;
		*)		output=$( grabdata_cache $confdir/$pkg.cache $field ) ;;
	esac
	if [ -z "${output// /}" ]; then
		echo "UNKNOWN"
	else
		echo "$output"
	fi
}
function grabdata_desc() {
	local output=
	if [ -f "$1" ]; then
		case "$2" in
			version)	output=$( grep -e "^\[V\]" $1 | cut -d' ' -f2- )	;;
		esac
	fi
	echo "$output"
}
function grabdata_cache() {
	local output=
	if [ -f "$1" ]; then
		case "$2" in
			status)	if grep -q -e "^\[.-ERROR\]" $1; then
					output=BROKEN
				else
					output=BUILT
				fi	;;
			size)	output=$( grep -e "^\[SIZE\]" $1 | cut -d' ' -f2- )	;;
		esac
	fi
	echo "$output"
}
function compare_package() {
	local source=$1
	local fullpkg=${1##*/package/}
	local pkg=${1##*/}
	local target= x= missing=0

	local info=
	local srcver= srcstatus= srcsize=
	local tgtver= tgtstatus= tgtsize=

	shift;

	[ $ignrepo -eq 1 ] && fullpkg=$pkg

	srcver=$( grabdata $source $pkg version )
	srcstatus=$( grabdata $source $pkg status )
	srcsize=$( grabdata $source $pkg size )
	tgtver=
	tgtstatus=
	tgtsize=

	for x; do
		target=$( echo $x/package/*/$pkg | head -n 1 )
		if [ -d "$target" ]; then
			tgtver="$tgtver:$( grabdata $target $pkg version )"
			tgtstatus="$tgtstatus:$( grabdata $target $pkg status )"
			tgtsize="$tgtsize:$( grabdata $target $pkg size )"
		else
			tgtver="$tgtver:MISSING"
			tgtstatus="$tgtstatus:MISSING"
			tgtsize="$tgtsize:MISSING"
			missing=1
		fi
	done
	
	tgtver="${tgtver#:}"
	tgtstatus="${tgtstatus#:}"
	tgtsize="${tgtsize#:}"

	# do we have different versions?
	#
	equalver=1 equalstatus=1
	IFS=':' ; for x in $tgtver; do
		[ "$x" != "$srcver" ] && equalver=0
	done
	IFS=':' ; for x in $tgtstatus; do
		[ "$x" != "$srcstatus" ] && equalstatus=0
	done

	# optimize version and status if they are the same
	#
	if [ $equalver -eq 1 ]; then
		version=$srcver
	else
		version="$srcver -> $tgtver"
	fi
	
	if [ $equalstatus -eq 1 ]; then
		status="$srcstatus"
	else
		status="$srcstatus -> $tgtstatus"
	fi
	
	# acording to verbosity level, what info should i show?
	#
	if [ $verbose -eq 0 ]; then
		info="($version)"
	else
		info="($version) ($status) ($srcsize -> $tgtsize)"
	fi

	if [ $missing -eq 1 ]; then
		if [ $quiet -le 1 ]; then
			# New - the package is not available at target tree
			echo "N $fullpkg $info" 1>&2
			[ $dopatch -eq 1 ] && diff_package $source $target
		fi
	elif [ $equalver -eq 1 ]; then
		if [ $quiet -eq 0 ]; then
			# Equal - the versions and cache status are the same on both trees
			echo "E $fullpkg $info" 1>&2
			[ $dopatch -eq 1 ] && diff_package $source $target
		fi
	else
		# Modified - the version on both trees is different
		echo "M $fullpkg $info" 1>&2
		[ $dopatch -eq 1 ] && diff_package $source $target
	fi
}

if [ -z "$source" -o -z "$targets" ]; then
	show_usage; exit 1
fi

allexist=1
for x in $source $targets; do
	[ ! -d "$x/" ] && allexist=0; break
done

if [ $allexist -eq 1 ]; then
	echo -e "from: $source\nto..: $targets" 1>&2

	if [ "$repositories" ]; then
		for repo in $repositories; do
			for x in $source/package/$repo/*; do
				[ -d "$x" ] && ( compare_package $x $targets )
			done
		done
	elif [ "$packages" ]; then
		for pkg in $packages; do
			x=$( echo $source/package/*/$pkg | head -n 1 )
			[ -d "$x" ] && compare_package $x $targets
		done
	else
		for repo in $source/package/*; do
			for x in $repo/*; do
				[ -d "$x" ] && compare_package $x $targets
			done
		done
	fi
else
	show_usage
	exit 1
fi

