rpm/rpmsort
Sascha Peilicke c6226665ac Accepting request 69617 from Base:System
- rpmsort
  + Fix comparison function to match rpm (bnc#644515, thanks to
    Michael Schroeder).
  + Add --test option to verify result against zypper vcmp. (forwarded request 69563 from michal-m)

OBS-URL: https://build.opensuse.org/request/show/69617
OBS-URL: https://build.opensuse.org/package/show/openSUSE:Factory/rpm?expand=0&rev=126
2011-05-05 07:31:12 +00:00

103 lines
2.8 KiB
Perl

#! /usr/bin/perl -w
# This program 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 2
# 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, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
# USA.
use Getopt::Long qw(:config gnu_getopt);
sub do_rpm_cmp_versions {
my ($evr1, $evr2) = @_;
sub _rpm_cmp {
my ($s1, $s2) = @_;
return defined $s1 <=> defined $s2
unless defined $s1 && defined $s2;
my ($r, $x1, $x2);
do {
$s1 =~ s/^[^a-zA-Z0-9]+//;
$s2 =~ s/^[^a-zA-Z0-9]+//;
if ($s1 =~ /^\d/ || $s2 =~ /^\d/) {
$s1 =~ s/^(0*(\d*))//; $x1 = $2;
return -1 if $1 eq '';
$s2 =~ s/^(0*(\d*))//; $x2 = $2;
return 1 if $1 eq '';
$r = length $x1 <=> length $x2 || $x1 cmp $x2;
} else {
$s1 =~ s/^([a-zA-Z]*)//; $x1 = $1;
$s2 =~ s/^([a-zA-Z]*)//; $x2 = $1;
return 0
if $x1 eq '' && $x2 eq '';
$r = $x1 cmp $x2;
}
} until $r;
return $r;
}
my ($e1, $v1, $r1) = $evr1 =~ /^(?:(\d*):)?(.*?)(?:-([^-]*))?$/;
my ($e2, $v2, $r2) = $evr2 =~ /^(?:(\d*):)?(.*?)(?:-([^-]*))?$/;
my $r = _rpm_cmp($e1 || 0, $e2 || 0);
$r = _rpm_cmp($v1, $v2)
unless $r;
$r = _rpm_cmp($r1, $r2)
unless $r;
return $r;
}
my $reorder = sub { return @_ };
my $key = 0;
my $test = 0;
sub rpm_cmp_versions {
my ($evr1, $evr2) = @_;
chomp($evr1, $evr2);
my $res1 = do_rpm_cmp_versions($evr1, $evr2);
if ($test) {
open(my $fd, '-|', 'zypper', '--terse', 'versioncmp',
$evr1, $evr2) or die "zypper: $!\n";
my $res2 = <$fd>;
close($fd) or die "zypper: $!\n";
chomp $res2;
if ($res1 != $res2) {
my @operators = qw(< == >);
my $op1 = $operators[$res1 + 1];
my $op2 = $operators[$res2 + 1];
print STDERR "BUG: $evr1 $op1 $evr2 vs. zypper: $evr1 $op2 $evr2\n";
}
}
return $res1;
}
GetOptions ("r|reverse" => sub { $reorder = sub { return reverse @_ } },
"k|key=i" => \$key,
"test" => \$test)
or do {
print STDERR "Usage $0 [-r, --reverse] [-k N, --key=N] [--test]\n";
exit 1;
};
if ($key == 0) {
# Sort by entire lines
map { print } &$reorder(sort { rpm_cmp_versions($a, $b) } <>);
} else {
# Sort by field $key
my @data = map { [(split)[$key-1], $_] } <>;
map { print } &$reorder(map { $_->[1] }
sort { rpm_cmp_versions($a->[0], $b->[0]) } @data);
}