#!/usr/bin/perl -w

use strict;
use Symbol;
use Cwd qw(realpath getcwd);
use OpenBSD::PackageName;

# Returns an array with package names that are currently installed.
# The array does not separate the stem and the version/patch part.
sub read_installed_packages
{
	my $FH = gensym;
	my ($line, @pkgs);

	unless (open($FH, '-|', "pkg_info 2>&1 | cut -f 1 -d ' '")) {
		die "unable to spawn pkg_info command: $! ($?)\n";
	}

	while (defined($line = <$FH>)) {
		push @pkgs, $line;
	}
	close($FH);

	return @pkgs;
}

# Reads the output of a cvs update command and looks for changed Makefiles
# Makefiles that do not belong to a port are ignored.
sub read_cvslog ($$)
{
	my ($filename, $portsdir) = @_;
	my $FH = gensym;
	my ($line, @filelist);

	open($FH, '<', $filename)
	    or die "unable to open file '$filename': $! ($?)\n";

	# Read the whole changelog
	while (defined($line = <$FH>)) {
		# Skip those that are not patched or unchecked and that have
		# no modification to the Makefile.
		next if ($line !~ /^[PU] .*\/Makefile$/);

		# Cut it so that it fits our needs
		$line =~ s/^[PU] //g;

		# Leave out the subdirectories Makefiles
		next if ($line =~ m/^[^\/]*?\/Makefile/ );

		# Now we assume that the filelist is relative to PORTSDIR
		$line =~ s/\s*$//g;
		$line = $portsdir . '/' . $line;
		
		push @filelist, $line;
	}

	close($FH);

	return @filelist;
}

# Prints out usage information
sub usage
{
	print STDERR "USAGE: list_updated_ports.pl cvslog\n";
}

# Check if we have one argument
my $filename = shift;
if (! defined($filename)) {
	usage();
	die "No filename given.\n";
}

my $only_list_changed_ports = 1;

# Get the list of installed packages
my @pkg_names = read_installed_packages();

# Read the PORTSDIR environment variable or set it to the default if not set
my $portsdir = $ENV{'PORTSDIR'};
$portsdir = '/usr/ports' if (! defined $portsdir);

# Now read the filenames with the changed makefiles into an array
my @changed_makefiles = read_cvslog($filename, $portsdir);

# Prepare the stemlist 
my $stemlist = OpenBSD::PackageName::compile_stemlist(@pkg_names);


my @changed_ports;
my $cwd = getcwd();

# Now parse each Makefile and get the DISTNAME variable
foreach my $makefile (@changed_makefiles) {

	# Get the absolute path the makefile is in and chdir into it
	my $makefile_loc = realpath($makefile);
	$makefile_loc =~ s/\/Makefile//g;
	next unless chdir($makefile_loc);

	my $FH = gensym;
	next unless open($FH, '-|', "make show=PKGNAMES");

	my $pkgnames;
	while ($pkgnames = <$FH>) {
		# Kill the newline debris at the end of the line
		$pkgnames =~ s/\s*$//g;
		push @changed_ports, split(/[ ]/, $pkgnames);
	}
	close($FH);

}

# Go back to where we started
chdir $cwd;

foreach my $port (@changed_ports) {
	my $stem = OpenBSD::PackageName::splitstem($port);
	my @candidates;
	if (`uname -r` < 4.2) {
		@candidates = $stemlist->findstem($stem);
	} else {
		@candidates = $stemlist->find($stem);
	}

	# Skip the port if we do not have it installed
	next if (scalar @candidates == 0);

	# Pretty print it so that we have a good view about the changes:
	while (scalar @candidates) {
		my $c = pop @candidates;
		$c =~ s/\s*$//g;
		next if ($only_list_changed_ports && ($c eq $port));
		print $c . " -> " . $port . "\n";
	}
}
