On a debian linux box the directory /var/cache/apt/archives gradually fills up with every .deb file you have ever installed or have ever downloaded with the option of installing. If a file corresponds to your currently installed version or is currently the most advanced version of that package you have available then you want to keep it, otherwise it’s redundant and may as well be deleted.

For example, let’s say I have 12 versions of bash sitting in that directory; the first 8 are previous versions, the 9th is the installed version, and the last 3 are versions I have downloaded but not gotten to the point of actually installing. In that case I want to keep the 9th and 12th files and delete the other 10.

Here is a perl script that will do exactly that. You could have a nightly script that did

apt-get update
apt-get upgrade --download-only -qq

then ran the following clean up script, then emailed you the list of packages having upgrades available.

#!/usr/bin/perl

use strict;
use warnings;

use Dpkg::Version qw(version_compare);

my %installed = ();

eval {
    my $pid = open(STATUS, '/usr/bin/dpkg-query -l | /bin/grep ^i |')
        or die 'Failed to get package status feed';
    while (defined($_ = )) {
        chomp;
        if (/^\w\w\s+(\S+)\s+(\S+)\s/) {
            $installed{$1} = $2;
        }
        else {
            die 'Unrecognised package status line';
        }
    }
    close(STATUS);
};
if ($@) {
    die "Failed to build list of installed versions\n". $@;
}

my %candidate = ( %installed );

eval {
    my $archive_dir = '/var/cache/apt/archives';
    opendir(AVAIL, $archive_dir)
        or die 'Failed to read archive dir';
    while (defined(my $deb = readdir(AVAIL))) {
        chomp $deb;
        if ($deb =~ /^([^_]+)_([^_]+)_/) {
            my ($p, $v) = ($1, $2);
            $v =~ s/%3a/:/g;
            if (exists $candidate{$p}) {
                my $cmp = version_compare($candidate{$p}, $v);
                if ($cmp  0) {
                    # Found a non-maximal version
                    unlink $deb
                        unless $installed{$p} && $installed{$p} eq $v;
                }
            }
            else {
                $candidate{$p} = $v;
            }
        }
        else {
            warn "Ignoring unrecognised file ($deb)";
        }
    }
    closedir(AVAIL);
};
if ($@) {
    die "Failed to build list of available versions\n". $@;
}

__END__
Advertisements

Whenever possible I try to stick to using the official debian-packaged distribution of a CPAN perl module, but occasionally that’s not possible, either because I need a fresher version or because nobody has packaged it for the official repos. There are three work-arounds I’m aware of…

I’ll put my favourite first: using debian.pkgs.cpan.org. Yes, by tweaking your /etc/apt/sources.list you have access to most of the CPAN modules you could want.

Second best (since it looks at dependencies too): using cpan2dist. However, the failures of trying to build CPANPLUS::Dist::Deb lead me to the first approach.

Third best (but a good start if you’re working on building a single properly-constructed debian package): using dh-make-perl.