I recently hacked up a quick-n-dirty helper for selectively mirroring or updating RPMs. The algorithm I wanted was
- collect the list available from the remote server;
- collect the list installed locally;
- for those packages available from the remote server, where the
same-name package is installed locally:
- ignore unless it's newer than what's installed locally;
- if multiple newer versions are offered, pick the newest
Those last two really put me off until I noticed that with Perl-RPM,
the invocation "use RPM qw(vercmp)" provides an RPM package version
comparison routine, hooray (the exact algorithm for comparing rpm
version strings is baroque).
When I got around to writing the thing, here's what came out. Sort
of an elaborated and extended Schwartzian Transform. The naughty
bits can be found quickly by searching for "map" and "sort". I
think the maps with big tagging regexps are particulary juicy.
I'm undecided whether this is good.
-Bennett
#!/usr/bin/perl -w
use strict;
=head1 NAME
rpm-mirror --- compute RPM files to download from http server
=head1 SYNOPSIS
rpm-mirror URL
=head1 DESCRIPTION
rpm-mirror compute the list of rpms available from the indicated
URL, which are "interesting", according to the following criteria,
and prints that list on stdout.
It compares that list with the list of rpms currently installed on
the local system; any rpms offered that don't have an rpm of the
same name installed locally, are ignored.
Any rpms offered for which the local version is newer or equal, are
ignored.
Of the remainder, the newest (greatest version/release) offered
version's URL is printed out, in full, on stdout. Reasonable
invocations for various contexts would include
rpm -U `rpm-mirror url`
and
rpm-mirror url|xargs wget -c
=cut
die "syntax: $0 URL\n" unless @ARGV == 1;
my $url = shift;
use LWP::Simple;
$_ = get($url) || die "$0: get($url) failed: $!\n";
# filename, pkgname, ver, rel
my @available = map { [ /^((.*)-([^-]+)-([^-]+)\.[^.]+\.rpm)$/ ] }
/<a\s+href="([^"]+\.rpm)"/gi;
# pkgname, ver, rel
my @installed = map { [ /^(.*)-([^-]+)-([^-]+)$/ ] } `rpm -qa`;
my %installed = map { $_->[0], $_ } @installed;
my %candidates;
use RPM qw(vercmp);
for (@available) {
my $name = $_->[1];
next unless exists($installed{$name});
next unless vercmp(@{$installed{$name}}[1,2], @{$_}[2,3]) < 0;
push @{$candidates{$name}}, $_;
}
$url =~ s/\/$//;
for (sort keys %candidates) {
if ($#{$candidates{$_}} == 0) {
print "$url/" . $candidates{$_}->[0][0] . "\n";
next;
}
my @sorted = map { $_->[0] } sort { vercmp(@{$b}[2,3], @{$a}[2,3]) }
@{$candidates{$_}};
print "$url/" . $sorted[0] . "\n";
}
msg02919/pgp00000.pgp
Description: PGP signature
