#!/usr/bin/perl

=pod

=head1 NAME

grip-selections.pl - compare a selection file against the current filter

=cut

use File::Basename;

=head1 Synopsis

 grip-selections.pl -b|--base PATH -f|--file FILE [--filter-name STRING]

 grip-selections.pl -?|-h|--help

=head1 Description

Originally designed for use by the administrator of the Grip repository,
this script could be modified to work for users too. The current
implementation reads in the content of a text file created with:

 $ dpkg --get-selections > selections.txt
 $ grip-selections -b ${base} -f selections.txt

This file is expected to be created on the device running Emdebian Grip
where the user has added packages from Debian and would like those
packages supported within Grip. The repository admin then uses this
routine to compare the requested package list against the current filter
and pick out the packages to add to the repository using em_autogrip.

(Note that the listed packages are binary packages - em_autogrip will
work out the relevant source package but only if the package data is
available using apt-cache on the machine running em_autogrip and
available via the mirror configured for use with em_autogrip.)

By using dpkg --get-selections, it is hoped that the list of packages
will automatically include all dependencies but this assumption will
break if the selection is old or not from a machine running unstable
or if the selection is pre-processed in some way.

The script could also use LWP to download the current filter file,
so that users could do the comparison themselves. If this would be
useful, please submit a wishlist bug against emdebian-grip asking
for this modification.

The base path is really only a path to the pkglist filter file
and is expected to be in $base/filter/conf/ so this mini-tree can be
replicated to test pkglist files from remote repositories.

=cut

=head1 Copyright and Licence

 Copyright (C) 2009  Neil Williams <codehelp@debian.org>

 This package 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; either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.

=cut

my $prog = basename($0);
$filter_name = 'filter';
my $www;

while( @ARGV ) {
	$_= shift( @ARGV );
	last if m/^--$/;
	if (!/^-/) {
		unshift(@ARGV,$_);
		last;
	}
	elsif (/^(-\?|-h|--help|--version)$/) {
		&usageversion();
		exit (0);
	}
	elsif (/^(-b|--base-path)$/) {
		$base = shift;
	}
	elsif (/^(--filter-name)$/) {
		$filter_name = shift;
	}
	elsif (/^(-f|--file)$/) {
		$file = shift;
	}
	elsif (/^(-w|--www)$/) {
		$www++;
	}
	else {
		die "$prog: Unknown option $_.\n";
	}
}

die "ERR: Please specify an existing directory for the base-path.\n"
	if (not defined $base and not defined $www);

$base .= '/' if ("$base" !~ m:/$:);
if (not -d $base and not defined $www)
{
	print "ERR: Please specify an existing directory for the base-path: $base";
	exit 1;
}
if (defined $www)
{
	my $dir = `mktemp -t -d "grip-select.XXXXXX"`;
	chomp ($dir);
	mkdir "$dir/conf";
	system ("wget -O $dir/conf/pkglist http://www.emdebian.org/grip/pkglist");
	$www = $dir;
	$base = $dir;
	$filter_name = "/";
}

%pkg=();
open (SELECT, "$file") or die ("ERR: No file: $file $!\n");
@lines=<SELECT>;
close (SELECT);
foreach $line (@lines)
{
	next unless $line =~ /install$/;
	next if $line =~ /deinstall$/;
	$line =~ s/\s+install$//;
	chomp($line);
	$pkg{$line}++;
}
open (SELECT, "${base}${filter_name}/conf/pkglist") or
	die ("ERR: No pkglist in ${base}${filter_name}/conf/: $!\n");
@filter=<SELECT>;
close (SELECT);
foreach $have (@filter)
{
	next unless $have =~ /install$/;
	$have =~ s/\s+install$//;
	chomp($have);
	delete $pkg{$have};
}
print "Of ".scalar (@lines)." selected packages, ";
print scalar (keys %pkg)." need to be added:\n";
print join (" ", sort keys %pkg)."\n";
print "\n";
if (defined $www and -d $www)
{
	$base = "/var/lib/apt";
	$filter_name = "";
}
if (-d "${base}${filter_name}/lists/")
{
	my %outside=();
	my %debian=();
	print "${base}${filter_name}/lists/\n";
	my $arch = `dpkg-architecture -qDEB_BUILD_ARCH_CPU`;
	chomp ($arch);
	my $list = `find "${base}${filter_name}/lists/" -name '*sid_main*Packages' -type f -ctime -7|grep -v uPackages|grep -m1 $arch`;
	chomp ($list);
	if ($list eq "")
	{
		print "failed with sid\n";
		$list = `find "${base}${filter_name}/lists/" -name '*unstable_main*Packages' -type f|grep -m1 $arch`;
		chomp ($list);
		print "list=:$list:\n";
	}
	if (-f "$list")
	{
		print "Checking $list\n";
		foreach my $p (sort keys %pkg)
		{
			print "Checking $p: ";
			my $avail = `grep-available -PX $p $list|grep -m1 Package|cut -d':' -f2`;
			chomp ($avail);
			if ($avail eq "")
			{
				print "Not in Debian.\n";
				$outside{$p}++;
			}
			else
			{
				print "Needs to be added to Emdebian.\n";
				$debian{$p}++;
			}
		}
		print scalar (keys %outside)." packages are not in Debian:\n";
		print join (" ", sort keys %outside)."\n";
		print scalar (keys %debian)." need to be added to Emdebian Grip:\n";
		print join (" ", sort keys %debian)."\n";
	}
}

if (defined $www and -d $www)
{
	system ("rm -rf $www");
}
exit 0;

sub usageversion
{
	print(STDERR <<END)
$prog - compare a selection file against the current filter

Syntax: $prog -b PATH -f FILE [--filter-name STRING]
        $prog -?|-h|--help|--version

Commands:
-b|--base-path PATH:        path to the top level grip directory
-f|--file FILE:             filename containing the selections [required]
-w|--www:                   use the current www.emdebian.org filter instead.

-?|-h|--help|--version:     print this help message and exit

Options:
   --filter-name STRING:    alternative name for the filter repository

END
	or die "$0: failed to write usage: $!\n";
}
