#!/usr/bin/perl -w
use strict;
use Getopt::Long;
my $mode;
my $matches = 1;
my %wikitxt = ("start" => "",
"end" => "",
"linestart" => "||",
"linemid" => "||",
"lineend" => "||",
"gt" => ">",
"lt" => "<",
"spc" => " ",
"f1fmt" => "%s",
"midfmt" => "%s"
);
my %htmltxt = ("start" => "
\n",
"linestart" => "| ",
"linemid" => " | ",
"lineend" => " |
",
"gt" => ">",
"lt" => "<",
"spc" => " ",
"f1fmt" => "%s",
"midfmt" => "%s"
);
my %texttxt = ("start" => "\n",
"end" => "",
"linestart" => "",
"linemid" => "",
"lineend" => "",
"gt" => ">",
"lt" => "<",
"spc" => "",
"f1fmt" => "%-40s",
"midfmt" => "%-3s"
);
my %txt = %wikitxt; #default to wiki
GetOptions("mode:s" => \$mode,
"matches!" => \$matches);
if (defined ($mode)){
# print "mode = $mode\n";
if ($mode !~ /text|html|wiki/) {
print "mode must be text/html/wiki\n";
exit 1;
}
if($mode eq "text") { %txt = %texttxt; } ;
if($mode eq "html") { %txt = %htmltxt; } ;
}
#take two parameters - the locations of the two merged repos
#these are the only two parameters left
if (!defined($ARGV[0]) || !defined($ARGV[1]))
{
print "Usage: $0 repo1 repo2\n";
print "Where repo1 and repo2 are the locations of the merged repo trees repomanage outputs\n";
exit 1;
}
#use repomanage to get a list of the latest packages in each
#my @repo1 = `repomanage $ARGV[0]`;
#my @repo2 = `repomanage $ARGV[1]`;
#output should already be sorted
open (REPO1, $ARGV[0]) || die "Cant open $ARGV[0]";
open (REPO2, $ARGV[1]) || die "Cant open $ARGV[0]";
my @repo1 = ();
my @repo2 = ();
my (%fc_pkg,%fc_version,%fc_release,%fc_arch, %fc_name,%fc_relnum, %fc_relrest,%fc_epoch);
my (%c_pkg,%c_version, %c_release,%c_arch, %c_name, %c_relnum, %c_relrest,%c_epoch);
my ($fc_count, $c_count);
my $repo1_dir="";
my $repo2_dir="";
my $idx = 1;
my $r1 = $repo1[0];
if ($r1 =~ /(.*\/)/)
{
$repo1_dir = $1;
}
foreach ( @repo1 ) {
#remove the location dir
s/$repo1_dir//;
# read the file list into hashes
chomp;
#break apart the name and store the values in the hashes
/(.+)\-(.+)\-(.+)\.(.+)\.rpm\:(.+)$/;
# print "package $_\n";
# print "name $1\n";
# print "version $2\n";
# print "release $3\n";
# print "arch $4\n";
$fc_pkg{$idx} = $_;
$fc_name{$idx} = $1;
$fc_version{$idx} = $2;
$fc_release{$idx} = $3;
$fc_arch{$idx} = $4;
$fc_epoch{$idx} = $5;
++$idx;
}
$fc_count = $idx;
#find the largest in fc_pkg to set the format string for printing
if ($mode eq "text") {
my $longest = 0;
for ($idx = 1; $idx < $fc_count ; $idx++)
{
if (length($fc_pkg{$idx}) > $longest)
{
$longest = length($fc_pkg{$idx});
}
}
$longest += 1;
$txt{'f1fmt'} = "%-".$longest."s";
}
$idx=1;
my $r2 = $repo2[0];
if ($r2 =~ /(.*\/)/)
{
$repo2_dir = $1;
}
foreach (@repo2) {
# read the file list into hashes
chomp;
s/$repo2_dir//;
/(.+)\-(.+)\-(.+)\.(.+)\.rpm\:(.+)$/;
$c_pkg{$idx} = $_;
$c_name{$idx} = $1;
$c_version{$idx} = $2;
$c_release{$idx} = $3;
$c_arch{$idx} = $4;
$c_epoch{$idx} = $5;
++$idx;
}
$c_count = $idx;
print "$txt{'start'}";
printf ("$txt{'f1fmt'}$txt{'midfmt'}%s","$txt{'linestart'}$ARGV[0]","$txt{'linemid'}$txt{'spc'}$txt{'linemid'}","$ARGV[1]$txt{'lineend'}\n");
if ($mode eq "text") { print "\n" };
my $pkg;
my $cidx= 1;
my $cmore;
for ($idx=1; $idx < $fc_count ; ++$idx )
{
# print "idx = $idx\n";
# print ("{1 = $fc_name{$idx} 2 = $c_name{$cidx}} ");
if (exists( $c_name{$cidx} ) ) {
if ($fc_name{$idx} le $c_name{$cidx})
{
if ($matches || ($c_pkg{$cidx} ne $fc_pkg{$idx}))
{
printf ($txt{'f1fmt'} , "$txt{'linestart'}$fc_pkg{$idx}");
}
}
$cmore = 0;
while ($c_name{$cidx} lt $fc_name{$idx})
{
# print (" ");
# these c ones dont exist in fc
printf("$txt{'f1fmt'}$txt{'midfmt'}%s", "$txt{'linestart'}","$txt{'spc'}$txt{'linemid'}$txt{'spc'}","$txt{'linemid'}$c_pkg{$cidx}$txt{'lineend'}\n");
$cmore =1;
++$cidx;
}
if($c_pkg{$cidx} eq $fc_pkg{$idx})
{
if ($matches)
{
printf ("$txt{'midfmt'}", "$txt{'linemid'}=$txt{'linemid'}");
}
else
{
++$cidx;
next;
}
}
}
else
{
printf("$txt{'f1fmt'}$txt{'midfmt'}%s","$txt{'linestart'}$fc_pkg{$idx}","$txt{'linemid'}$txt{'spc'}$txt{'linemid'}","$txt{'spc'}$txt{'lineend'}\n");
next;
}
if ( ! exists $c_name{$cidx} ) # no more left in c
{
if (!$cmore) { print "\n"; };
next;
}
if ($cmore)
{
--$idx;
next;
}
my $match = 0;
if ($c_name{$cidx} eq $fc_name{$idx})
{
# both exist
if($c_pkg{$cidx} eq $fc_pkg{$idx}) {
#printf ("$txt{'midfmt'}", "$txt{'linemid'}=$txt{'linemid'}");
}
else {
#use rpm2 to compare
# my $fc_ = RPM2->open_package( $repo1_dir.$fc_pkg{$idx} );
# my $c_ = RPM2->open_package( $repo2_dir.$c_pkg{$cidx} );
#print "\n\n$fc_pkg{$idx} $fc_epoch{$idx} $fc_version{$idx} $fc_release{$idx} --- $c_epoch{$cidx} $c_version{$cidx} $c_release{$cidx}";
if ($fc_epoch{$idx} > $c_epoch{$cidx}) {
printf ("$txt{'midfmt'}", "$txt{'linemid'}E>$txt{'linemid'}");
}
elsif ($fc_epoch{$idx} < $c_epoch{$cidx}) {
printf ("$txt{'midfmt'}", "$txt{'linemid'} 0) {
printf ("$txt{'midfmt'}", "$txt{'linemid'}$txt{'gt'}$txt{'linemid'}");
}
else {
printf ("$txt{'midfmt'}", "$txt{'linemid'}=$txt{'linemid'}" );
};
}
else {
if ( rpmvercmp($fc_version{$idx},$c_version{$cidx}) < 0 ) {
printf ("$txt{'midfmt'}", "$txt{'linemid'}$txt{'lt'}$txt{'lt'}$txt{'linemid'}");
}
else {
printf ("$txt{'midfmt'}", "$txt{'linemid'}$txt{'gt'}$txt{'gt'}$txt{'linemid'}");
}
}
}
}
print "$c_pkg{$cidx}$txt{'lineend'}\n";
++$cidx;
$match = 1;
}
else
{
printf("$txt{'f1fmt'}$txt{'midfmt'}","$txt{'linestart'}","$txt{'spc'}$txt{'linemid'}$txt{'spc'}");
}
if(exists($c_name{$cidx+1}))
{
if ($c_name{$cidx+1} gt $fc_name{$idx} && !$match && !$cmore)
{
print "$txt{'lineend'}\n";
}
}
}
#there may still be stuff left in cidx
for (; $cidx < $c_count ; ++$cidx )
{
printf ("$txt{'f1fmt'}$txt{'midfmt'}%s","$txt{'linestart'}","$txt{'spc'}$txt{'linemid'}$txt{'spc'}","$txt{'linemid'}$c_pkg{$cidx}$txt{'lineend'}\n");
}
print $txt{'end'};
#
# 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;
}
}