merge_rpms
#!/usr/bin/perl -w
#
# after the redhat update directories are mirrored
# remove old RPMS from RPM directory, link to new
# ones in update dirs (assumes we always want to
# replace older versions with newer ones)
#
use strict;
use File::stat;
my $rhdir = "/usr/local/misc"; # base directory
my $rpm_dir = "$rhdir/RedHat/RPMS"; # "master" RPM directory
my $update_base = "$rhdir/updates"; # update base directory
my @update_dirs = ( # list of directories containing update RPMS
"$update_base/athlon",
"$update_base/i386",
"$update_base/i586",
"$update_base/i686",
"$update_base/noarch"
);
my $current_rpm; # single RPM filename
my $rpmout; # output from rpm -qp command
my $sb; # stat output
my $update_dir; # update directory path
my $update_rpm; # update RPM filename
my %current_release; # release of each RPM
my %current_version; # version of each RPM
my %filename; # filename of each RPM
my %path; # path to each unique RPM
my ( $name, $version, $release, $arch ); # split-up output from query
my @current_rpms; # list of RPM files in directory
my @update_rpms; # list of update RPM files in directory
opendir( D, $rpm_dir ) || die "Opening $rpm_dir failed: $!\n";
@current_rpms = grep { /\.rpm$/ } readdir(D);
closedir(D);
foreach $current_rpm (@current_rpms) {
$rpmout =
`rpm -qp --queryformat '%{NAME} %{VERSION} %{RELEASE} %{ARCH}\n' $rpm_dir/$current_rpm`;
chomp $rpmout;
( $name, $version, $release, $arch ) = split ( / /, $rpmout );
#
# this assumes that the $name - $arch tuple is different for
# each current RPM in the CD image...
#
$path{"$name $arch"} = "$rpm_dir/$current_rpm";
$current_version{"$name $arch"} = $version;
$current_release{"$name $arch"} = $release;
$filename{"$name $arch"} = $current_rpm;
}
foreach $update_dir (@update_dirs) {
opendir( D, $update_dir ) || die "Opening $update_dir failed: $!\n";
@update_rpms = sort grep { /\.rpm$/ } readdir(D);
closedir(D);
foreach $update_rpm (@update_rpms) {
$sb = stat("$update_dir/$update_rpm");
next if $sb->nlink == 2; # already linked
$rpmout =
`rpm -qp --queryformat '%{NAME} %{VERSION} %{RELEASE} %{ARCH}\n' $update_dir/$update_rpm`;
chomp $rpmout;
( $name, $version, $release, $arch ) = split ( / /, $rpmout );
unless ( $filename{"$name $arch"} ) {
print "NO rpm in $rpm_dir matching $update_rpm\n";
next;
}
if (
rpmvercmp( $version, $current_version{"$name $arch"} ) > 0
|| ( rpmvercmp( $version, $current_version{"$name $arch"} ) == 0
&& rpmvercmp( $release, $current_release{"$name $arch"} ) > 0 )
)
{
printf " ... replacing %s with %s ...\n",
$filename{"$name $arch"}, $update_rpm;
unlink $path{"$name $arch"};
link( "$update_dir/$update_rpm", "$rpm_dir/$update_rpm" )
|| die "Ack! link failed: $!\n";
$path{"$name $arch"} = "$rpm_dir/$update_rpm";
$filename{"$name $arch"} = $update_rpm;
$current_version{"$name $arch"} = $version;
$current_release{"$name $arch"} = $release;
}
else {
print "NOT replacing ", $filename{"$name $arch"},
" with (apparently older) $update_rpm\n";
}
}
}
print "Running genhdlist...\n";
system("/usr/lib/anaconda-runtime/genhdlist $rhdir");
chmod( 0644, <$rhdir/RedHat/base/hdlist*> )
|| warn "Chmod failed: $!\n";
#
# parse Red Hat RPM release/version strings into tokens
#
sub rpmverparse {
my ($ver) = @_;
my @verparts = ();
while ( $ver ne "" ) {
if ( $ver =~ /^([A-Za-z]+)/ ) { # leading letters
push ( @verparts, $1 );
$ver =~ s/^[A-Za-z]+//;
}
elsif ( $ver =~ /^(\d+)/ ) { # leading digits
push ( @verparts, $1 );
$ver =~ s/^\d+//;
}
else { # remove non-letter, non-digit
$ver =~ s/^.//;
}
}
return @verparts;
}
#
# compare Red Hat RPM release/version strings
#
sub rpmvercmp {
my ( $a, $b ) = @_;
my @aparts; # list of version/release tokens
my @bparts;
my $apart; # individual token from array
my $bpart;
my $result;
if ( $a eq $b ) {
return 0;
}
@aparts = rpmverparse($a);
@bparts = rpmverparse($b);
while ( @aparts && @bparts ) {
$apart = shift (@aparts);
$bpart = shift (@bparts);
if ( $apart =~ /^\d+$/ && $bpart =~ /^\d+$/ ) { # numeric
if ( $result = ( $apart <=> $bpart ) ) {
return $result;
}
}
elsif ( $apart =~ /^[A-Za-z]+/ && $bpart =~ /^[A-Za-z]+/ ) { # alpha
if ( $result = ( $apart cmp $bpart ) ) {
return $result;
}
}
else { # "arbitrary" in original code
return -1;
}
}
if (@aparts) { # left over stuff in a, assume it's newer
return 1;
}
elsif (@bparts) { # leftover in b, assume it's newer
return -1;
}
else { # "should never happen"
return 0;
}
}