#!/bin/sh

# Selectively remove redundant matched .deb packages,
# we check in/under current directory, and check for matches against
# our typical other locations we may have such files.

# vi(1) :se tabstop=4

set -e

# set d and i to dev and inode of .:
eval $(stat -L -c 'd=%d i=%i' .)
# and check they're set:
[ -n "$d" ]
[ -n "$i" ]
# we use this later to exclude comparing stuff under current directory
# to other stuff under current directory ... we do this so we
# can avoid removing stuff in/under . if it only matches to stuff
# in/under .

# basenames of the files, and their relative paths, under .:
names_paths=$(
	find . -xdev -name '*.deb' -type f -print 2>>/dev/null |
	sed -e '
		s/^\.\///
		s/^.*\/\([^\/]\{1,\}\)$/\1 &/
		/ /!{s/.*/& &/}
	'
)

[ -n "$names_paths" ] # fail if we got none

# start building our find -name ... filter expression
namefilter=$(
	sed -e '
		s/ .*$//
		/^$/d
	' <<- __EOT__ |
		$names_paths
	__EOT__
	sort -u |
	awk '
		{if(NR>1)printf(" -o ")}
		{printf("-name %s",$0)}
	'
)

[ -n "$namefilter" ] # fail if we got none

# look for matched names in customary locations,
# use similar format - basename, and path - path being absolute in this case
NAMES_PATHS=$(
	find \
		/media/cdrom*/ \
		/var/cache/apt/archives \
		/var/local/cache \
		\( \
			-inum "$i" -type d -exec \
			sh -c 'test '"$d"' -eq $(stat -L -c %d {})' \; -prune \
		\) \
		-o \
		\( \
			\( $namefilter \) -type f -print \
		\) \
		2>>/dev/null \
		|
		sed -e '
			s/^\.\///
			s/^.*\/\([^\/]\{1,\}\)$/\1 &/
			/ /!{s/.*/& &/}
		'
)

[ -n "$NAMES_PATHS" ] || exit 0 # no possible matches, exit successfully (nothing to do, and not an error)

# Take that earlier data we got of what we have and might possibly match
# it to, and rearrange/reformat output lines, so for each line,
# first field is basename, subsequent fields are relative (under .) and
# absolute (starting with /) pathnames, the former stuff we will check
# if redundant and remove, the later is our customary locations of
# possible matches.
# We skip outputing the line if there are no absolute paths for the
# corresponding basename file (no possible matches, as we're looking
# for stuff in our customary locations relative to absolute path(s)).
sed -e '/^$/d' <<- __EOT__ |
	$names_paths
	$NAMES_PATHS
__EOT__
perl -e '
	$^W=1;
	use strict;
	my %np=();
	while(<>){
		chomp;
		/\A([^ ]+) ([^ ]+)\z/ or next;
		$np{$1}{$2}=undef;
	};
	for my $name (keys %np){
		my @names=($name);
		my $absolute=0;
		for my $path (
			sort
				{
					if($a =~ m:^/:){
						if($b !~ m:^/:){
							1
						}else{
							0
						}
					}else{
						if($b =~ m:^/:){
							-1
						}else{
							0
						}
					}
				}
				keys %{$np{$name}}
		){
			$absolute=1 if $path =~ m:^/:;
			push(@names,$path);
		}
		print(join(q( ),@names),"\n") if $absolute;
	};
' |
# each line of input, basename of file, and fields of paths to possibly
# match, with at least one absolute and one or more relative pathnames.
while read line
do
	set -- $line
	name="$1"; shift # shift out the basename
	# build our set for the line, of absolute(s) and relative(s):
	absolutes=
	relatives=
	while [ "$#" -ge 1 ]; do
		case "$1" in
			/*)
				absolutes="${absolutes:+$absolutes }$1"
			;;
			*)
				relatives="${relatives:+$relatives }$1"
			;;
		esac
		shift
	done
	[ -n "$absolutes" ] || continue # next if none to process
	[ -n "$relatives" ] || continue # next if none to process
	# for each line,
	# compare each relative to the absolute(s),
	# if matched, remove relative and skip to next relative
	for r in $relatives; do
		for a in $absolutes; do
			cmp "$r" "$a" >>/dev/null 2>&1 && {
				rm "$r"
				continue 2
			}
		done
	done
done
