#!/usr/bin/perl
$^W=1;
use strict;

# sumarize select output of aptitude (e.g. aptitude safe-upgrade).

my %index=();	# track references to package
my %packages=();	# track packages referenced

# index count on potential lines or portions thereof we consider
my $i=0;

while(<>){

	# missing newline, strip as work-around
	s/^Reloading web server config: apache2//o;

	s/[\ \t\n\r]+$//o;	# strip trailing blanks, tabs, newlines, CRs
	next if /^$/o;		# skip if empty

	# split at one or more CRs and handle each part
	for(split(/\r+/o,$_)){
		s/[\ \t]+$//o;	# strip trailing blanks and/or tabs
		next if /^$/o;	# skip if empty
		++$i;
		if(
			# where we typically track replaced package and version
			/^Preparing to replace ([^ ]+) ([^ ]+) \(using \.\.\.\//
		){
			$index{$i}=$1;
			if(exists($packages{$1}{index})){
				push(@{$packages{$1}{index}},$i);
			}else{
				$packages{$1}{index}=[$i];
			};
			if(
				exists($packages{$1}{remove}) &&
				defined($packages{$1}{remove})
			){
				die(
					"$0: mismatched package version remove: $1: " .
					"$packages{$1}{remove} vs. $2\n"
				) if $packages{$1}{remove} ne $2;
			}else{
				$packages{$1}{remove}=$2;
			};
			#print "Preparing_to_replace $1 $2\n";
		}elsif(
			# where we typically track added package and version
			/^Setting up ([^\ ]+) \(([^)]+)\Q) ...\E/o
		){
			$index{$i}=$1;
			if(exists($packages{$1}{index})){
				push(@{$packages{$1}{index}},$i);
			}else{
				$packages{$1}{index}=[$i];
			};
			if(exists($packages{$1}{add})){
				die(
					"$0: mismatched package version adds: $1: " .
					"$packages{$1}{add} vs. $2\n"
				) if $packages{$1}{add} ne $2
				;
			}else{
				$packages{$1}{add}=$2;
			};
			#print "Setting_up $1 $2\n";
		}elsif(
			/^Removing ([^\ ]+) \.\.\.$/o
		){
			$index{$i}=$1;
			if(exists($packages{$1}{index})){
				push(@{$packages{$1}{index}},$i);
			}else{
				$packages{$1}{index}=[$i];
			};
			if(!exists($packages{$1}{remove})){
				$packages{$1}{remove}=undef;
			};
		}elsif(
			/^Purging configuration files for ([^\ ]+) \.\.\.$/
		){
			$index{$i}=$1;
			if(exists($packages{$1}{index})){
				push(@{$packages{$1}{index}},$i);
			}else{
				$packages{$1}{index}=[$i];
			};
			if(!exists($packages{$1}{purge})){
				$packages{$1}{purge}=undef;
			};
		}elsif(
			# stuff that's uninteresting to us
			/
				^
				(?:
					Unpacking\ replacement\ [^\ ]+\ \.\.\.$ |
					gpg: |
					Processing\ triggers\ for\ [^\ ]+\ \.\.\.$ |
					\(Reading\ database\ \.\.\.\ \d+\ files\ and\ 
						directories\ currently\ installed\.\)$ |
					Unpacking\ [^\ ]+\ \(from\ \.\.\.\/[^\ ]+\)\ \.\.\.$ |
					Selecting\ previously\ deselected\ package\ ([^\ ]+)\.$ |
					(?:Universal|Local)\ [Tt]ime\ is\ now: |
					St(?:art|opp)ing\ web\ server:\  |
					Run\ 'dpkg-reconfigure\ tzdata'\ if\ you\ wish\ to\ 
						change\ it\.$ |
					Installing\ new\ version\ of\ config\ file\ 
						\/etc\/debian_version\ \.\.\.$ |
					Current\ default\ time\ ?zone:\  |
					\(Reading database \.\.\. \d+ files and directories currently installed\.\)$ |
					Updating\ fontconfig\ cache\ for\ |
					Reading\ changelogs |
					(?:Stopping|Starting)\ |
					Building\ dependency\ tree |
					Cleaning\ up\ |
					Generating\ |
					Initializing\ |
					(?:Reading|Writing)\ (?:extended\ )?state\ information |
					Reading\ package\ lists\.\.\. |
					Updating\ 
				)
			/ox
		){
			next;
		}else{
			warn "$0: WARN: $_\n";
		};
	};
};

# report on what happened
# determine summary information from last event to first,
# then report first to last

my @report=();

for my $i (sort { $b <=> $a } (keys %index)){
	#print "$i\n";
	my $package=$index{$i};
	#print "$i $package\n";
	if(exists($packages{$package})){
		my $old=undef;
		if(defined($packages{$package}{remove})){
			$old=$packages{$package}{remove};
		}elsif(defined($packages{$package}{purge})){
			$old=$packages{$package}{purge};
		}elsif(exists($packages{$package}{remove})){
			$old='';
		}elsif(exists($packages{$package}{purge})){
			$old='';
		};
		my $new=undef;
		if(defined($packages{$package}{add})){
			$new=$packages{$package}{add};
		}elsif(exists($packages{$package}{add})){
			$new='';
		};
		if(defined($new)){
			# installed or upgraded
			if(defined($old)){
				# upgraded
				unshift(
					@report,
					'upgraded ' . $package .
					(
						$old ne ''
						?
						' version ' . $old
						:
						''
					) .
					(
						$new ne ''
						?
						' to version ' . $new
						:
						''
					) .
					"\n"
				);
			}else{
				# installed
				unshift(
					@report,
					'installed ' . $package .
					(
						$new ne ''
						?
						' version ' . $new
						:
						''
					) .
					"\n"
				);
			};
		}elsif(defined($old)){
			# removed or purged
			unshift(
				@report,
				(
					exists($packages{$package}{purge})
					?
					'purged'
					:
					'removed'
				) . ' ' .
				$package .
				(
					$old ne ''
					?
					' version ' . $old
					:
					''
				) .
				"\n"
			);
		}else{
			die "$0: package $package has neither add nor remove nor purge?\n";
		};
	}else{
		#already processed
		next;
	};
	delete($packages{$package});	# done reporting on that package
};

print (@report);
