#!/bin/sh -e
# "Daddy, I wanna be a perl script when I grow up.."
#
# Compares two unpacked trees, and finds and flags added files,
# files that have increased in size, and so on.

if [ ! "$1" -o ! "$2" ]; then
	echo "Usage: $0 oldtree newtree" >&2
	exit 1
fi

oldtree=$1
newtree=$2

# Special case hack: rename lib/modules/k.ver.sion to lib/modules/x.y.zz, to
# facilitate seeing changes inside the modules tree over kernel versions.
oldmod=$(echo $oldtree/lib/modules/*)
mv $oldmod $oldtree/lib/modules/x.y.zz
newmod=$(echo $newtree/lib/modules/*)
mv $newmod $newtree/lib/modules/x.y.zz

# $1 = command to run ($tree is substitutued)
# $2 = optional units
# Sets as a size effect $change to the difference netween new and old.
compare () {
	tree=$oldtree
	oldval=$(eval "$1")
	tree=$newtree
	newval=$(eval "$1")
	if [ $oldval -lt $newval ]; then
		echo "added $(($newval - $oldval))$2"
	elif [ $oldval -gt $newval ]; then
		echo "removed $(($oldval - $newval))$2"
	else
		echo "unchanged"
	fi
	change=$(($newval - $oldval))
}

sortbysize () {
	perl -e '
		$basedir=shift;
		%filesize=map {
			chomp;
			$file=$_;
			$file=~s/^\s+//;
			$file="$basedir/$file";
			$size=0;
			if (-d $file) {
				$size=`du -b -s $file`;
				chomp $size;
				$size=~s/\s.*//;
			}
			elsif (! -l $file) {
				$size=-s $file;
			}
			"\t$size:\t$_\n" => $size;
		} <>;
		print sort { $filesize{$b} <=> $filesize{$a} } keys %filesize
	' $newtree
}

echo -n "Size:		"
compare 'du -k -s $tree | cut -d "	" -f 1' 'k'
sizechange=$change
echo -n "Dir count:	"
compare 'find $tree -type d | wc -l'
dirchange=$change
echo -n "File count:	"
compare 'find $tree -not -type d | wc -l'
filechange=$change
echo

if [ $sizechange -gt 0 ]; then
	echo "Bigger directories:"
	# A better man than I may be able to do this in shell..
	perl -e '
		$dir2=shift()."/";
		$dir1=shift()."/";
		%du=map {chomp;s/$dir1//;reverse split " ", $_, 2} `du -b $dir1`;
		%du2=map {chomp;s/$dir2//;reverse split " ", $_, 2} `du -b $dir2`;
		foreach (sort { $du{$b} <=> $du{$a} } keys %du) {
			next unless exists $du2{$_};
			next if $du{$_} <= $du2{$_};
			print "\t".($du{$_} - $du2{$_}).":\t/$_\n"
		}
	' $oldtree $newtree | sort -rn
	echo

	echo "Bigger files:"
	perl -e '
		$dir2=shift()."/";
		$dir1=shift()."/";
		%files=map {chomp; $file=$_; s/^$dir1//; $_ => -s $file }
			`find $dir1 -type f`;
		%files2=map {chomp; $file=$_; s/^$dir2//; $_ => -s $file }
			`find $dir2 -type f`;
		foreach (sort { $files{$b} <=> $files{$a} } keys %files) {
			next unless exists $files2{$_};
			next if $files{$_} <= $files2{$_};
			print "\t".($files{$_} - $files2{$_}).":\t/$_\n"
		}
	' $oldtree $newtree | sort -rn
	echo
fi

echo "New stuff (biggest first):"
diff -rq $oldtree $newtree | fgrep "in $newtree" | sed "s!Only in $newtree\(.*\): !\1/!" | sortbysize
echo

echo "Removed stuff:"
diff -rq $oldtree $newtree | fgrep "in $oldtree" | sed "s!Only in $oldtree\(.*\): !	\1/!"
echo

# Clean up.
mv $newtree/lib/modules/x.y.zz $newmod
mv $oldtree/lib/modules/x.y.zz $oldmod