From owner-freebsd-ports Tue Mar 27 18:37:46 2001 Delivered-To: freebsd-ports@freebsd.org Received: from sj-msg-core-2.cisco.com (sj-msg-core-2.cisco.com [171.69.43.88]) by hub.freebsd.org (Postfix) with ESMTP id E188F37B719; Tue, 27 Mar 2001 18:37:30 -0800 (PST) (envelope-from bmah@cisco.com) Received: from bmah-freebsd-0.cisco.com (bmah-freebsd-0.cisco.com [171.70.84.42]) by sj-msg-core-2.cisco.com (8.9.3/8.9.1) with ESMTP id SAA14626; Tue, 27 Mar 2001 18:37:52 -0800 (PST) Received: (from bmah@localhost) by bmah-freebsd-0.cisco.com (8.11.3/8.11.1) id f2S2bUP02277; Tue, 27 Mar 2001 18:37:30 -0800 (PST) (envelope-from bmah) Message-Id: <200103280237.f2S2bUP02277@bmah-freebsd-0.cisco.com> X-Mailer: exmh version 2.3.1 01/19/2001 with nmh-1.0.4 To: freebsd-ports@freebsd.org, knu@freebsd.org Cc: bmah@freebsd.org Subject: pkg_version comparison routine From: bmah@freebsd.org (Bruce A. Mah) Reply-To: bmah@freebsd.org X-Face: g~c`.{#4q0"(V*b#g[i~rXgm*w;:nMfz%_RZLma)UgGN&=j`5vXoU^@n5v4:OO)c["!w)nD/!!~e4Sj7LiT'6*wZ83454H""lb{CC%T37O!!'S$S&D}sem7I[A 2V%N&+ X-Image-Url: http://www.employees.org/~bmah/Images/bmah-cisco-small.gif X-Url: http://www.employees.org/~bmah/ Mime-Version: 1.0 Content-Type: multipart/signed; boundary="==_Exmh_-1096974478P"; micalg=pgp-sha1; protocol="application/pgp-signature" Content-Transfer-Encoding: 7bit Date: Tue, 27 Mar 2001 18:37:30 -0800 Sender: owner-freebsd-ports@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org --==_Exmh_-1096974478P Content-Type: text/plain; charset=us-ascii Howdy. I'm going to revisit an issue long overdue...the fact that the algorithm used by pkg_version(1) for comparing versions doesn't work in all the cases specified by the Porter's Handbook. knu tried to get my attention on this issue a number of months ago, even going so far as to submit some patches to fix this problem. Unfortunately I dropped the ball on this, and I'm sure he's understandably annoyed at me. Let me apologize now to knu for my being a bad maintainer and ignoring his email. I'm sorry...and I didn't mean it personally. What I've done is to take some of knu's code and ideas and to try to cover what the Porter's Handbook does, plus one or two other cases I've seen (plus, admittedly, rewrite it so that my meager Perl skills stand a chance of maintaining it in the future). I also took a variant of his -t feature. I've got a new version now that handles all the forms of version numbers below: 1.0.5 The usual, run-of-the mill version number. 1.0.b2 Recommended form for "1.0beta2". 1.0c Not allowed by the Porter's Handbook, but plenty of ports use this syntax. Should be "1.0.c". 1.0.b2c A combination of the preceding two cases. Again, not technically allowed. (The use of PORTEPOCH and PORTREVISION are of course supported; they're actually orthogonal, as the code is implemented.) The -t option below is a little different than what knu did originally; what this version does is to take two version strings and return "=", "<", or ">" on standard out. (knu's version took a test and returned a truth value for the test.) I've got a usage in mind where I think that this form of -t will be more useful. The following is a patch against the RELENG_4 branch, but it should apply equally well to the HEAD. Comments would be most welcome. Thanks, Bruce. ? pkg_version.ps ? pkg_version.diff Index: pkg_version.1 =================================================================== RCS file: /home/ncvs/src/usr.sbin/pkg_install/version/pkg_version.1,v retrieving revision 1.5.2.8 diff -c -r1.5.2.8 pkg_version.1 *** pkg_version.1 2001/02/20 23:32:50 1.5.2.8 --- pkg_version.1 2001/03/28 02:13:43 *************** *** 36,41 **** --- 36,43 ---- .Op Fl l Ar limchar .Op Fl L Ar limchar .Op Ar index + .Nm pkg_version + .Op Fl t Ar version1 version2 .Sh DESCRIPTION The .Nm *************** *** 144,149 **** --- 146,161 ---- to the shell, it is best to quote .Ar limchar with single quotes. + .It Fl t + Test a pair of version number strings and exit. + The output consists of one of the single characters + .Li = + (equal), + .Li \&< + (right-hand number greater), or + .Li \&> + (left-hand number greater) on standard output. + This flag is mostly useful for scripts or for testing. .It Fl v Enable verbose output. Verbose output includes some English-text interpretations of the version number comparisons, as well as the *************** *** 198,214 **** unusable state. .Pp .Dl % pkg_version -c > do_update .Sh AUTHORS .An Bruce A. Mah Aq bmah@FreeBSD.org .Sh CONTRIBUTORS .An Nik Clayton Aq nik@FreeBSD.org , .An Dominic Mitchell Aq dom@palmerharvey.co.uk , .An Mark Ovens Aq marko@FreeBSD.org , ! .An Doug Barton Aq DougB@gorean.org .Sh BUGS - .Pp - Patch levels aren't handled - very well (i.e. version numbers of the form 1.2p3 or 1.2pl3). .Pp The commands output feature is .Bf Em --- 210,228 ---- unusable state. .Pp .Dl % pkg_version -c > do_update + .Pp + The following command compares two package version strings: + .Pp + .Dl % pkg_version -t 1.5 1.5.1 .Sh AUTHORS .An Bruce A. Mah Aq bmah@FreeBSD.org .Sh CONTRIBUTORS .An Nik Clayton Aq nik@FreeBSD.org , .An Dominic Mitchell Aq dom@palmerharvey.co.uk , .An Mark Ovens Aq marko@FreeBSD.org , ! .An Doug Barton Aq DougB@gorean.org , ! .An Akinori MUSHA Aq knu@FreeBSD.org .Sh BUGS .Pp The commands output feature is .Bf Em Index: pkg_version.pl =================================================================== RCS file: /home/ncvs/src/usr.sbin/pkg_install/version/pkg_version.pl,v retrieving revision 1.4.2.7 diff -c -r1.4.2.7 pkg_version.pl *** pkg_version.pl 2001/02/16 17:52:34 1.4.2.7 --- pkg_version.pl 2001/03/28 02:13:43 *************** *** 37,43 **** # # Configuration global variables # - $Version = '0.1'; $CurrentPackagesCommand = '/usr/sbin/pkg_info -aI'; $CatProgram = "cat "; $FetchProgram = "fetch -o - "; --- 37,42 ---- *************** *** 62,70 **** # This function returns -1, 0, or 1, in the same manner as <=> or cmp. # sub CompareNumbers { ! local($v1, $v2); ! $v1 = $_[0]; ! $v2 = $_[1]; # Short-cut in case of equality if ($v1 eq $v2) { --- 61,67 ---- # This function returns -1, 0, or 1, in the same manner as <=> or cmp. # sub CompareNumbers { ! my ($v1, $v2) = @_; # Short-cut in case of equality if ($v1 eq $v2) { *************** *** 73,99 **** # Loop over different components (the parts separated by dots). # If any component differs, we have the basis for an inequality. ! while (1) { ! ($p1, $v1) = split(/\./, $v1, 2); ! ($p2, $v2) = split(/\./, $v2, 2); ! ! # If we\'re out of components, they\'re equal (this probably won\'t ! # happen, since the short-cut case above should get this). ! if (($p1 eq "") && ($p2 eq "")) { ! return 0; ! } ! # Check for numeric inequality. We assume here that (for example) ! # 3.09 < 3.10. ! elsif ($p1 != $p2) { ! return $p1 <=> $p2; } ! # Check for string inequality, given numeric equality. This ! # handles version numbers of the form 3.4j < 3.4k. ! elsif ($p1 ne $p2) { ! return $p1 cmp $p2; } } } # --- 70,159 ---- # Loop over different components (the parts separated by dots). # If any component differs, we have the basis for an inequality. ! my @s1 = split(/\./, $v1); ! my @s2 = split(/\./, $v2); ! my ($c1, $c2); ! do { ! last unless @s1 || @s2; ! $c1 = shift @s1; ! $c2 = shift @s2; ! } while ($c1 eq $c2); ! ! # Look at the first components of the arrays that are left. ! # These will determine the result of the comparison. ! # Note that if either version doesn't have any components left, ! # it's implicitly treated as a "0". ! ! # Our next set of checks looks to see if either component has a ! # leading letter (there should be at most one leading letter per ! # component, so that "4.0b1" is allowed, but "4.0beta1" is not). ! if ($c1 =~ /^\D/) { ! if ($c2 =~ /^\D/) { ! ! # Both have a leading letter, so do an alpha comparison ! # on the letters. This isn't ideal, since we're assuming ! # that "1.0.b4" > "1.0.a2". But it's about the best we can do, ! # without encoding some explicit policy. ! $letter1 = substr($c1, 0, 1); ! $letter2 = substr($c2, 0, 1); ! ! if ($letter1 ne $letter2) { ! return $letter1 cmp $letter2; ! } ! else { ! # The letters matched equally. Delete the leading ! # letters and do an alpha comparison on the remaining ! # characters, which according to the Porters Handbook ! # must be digits, so for example, "1.0.a9" < "1.0.a10". ! substr($c1, 0, 1) = ""; ! substr($c2, 0, 1) = ""; ! ! # We copy, without further comment, the code from the ! # case below where we handle purely numeric comparisons. ! # This covers comparisons of the form "1.0.a9a" < "1.0.a9b" ! # (not allowed by the Porters Handbook, but seen in real ! # code), as well as the intended "1.0.a9" < "1.0.a10". ! if ($c1 != $c2) { ! return $c1 <=> $c2; ! } ! else { ! return $c1 cmp $c2; ! } ! } ! } ! else { ! # $c1 begins with a letter, but $c2 doesn't. Let $c2 ! # win the comparison, so that "1.0.b1" < "1.0.1". ! return -1; } } + else { + if ($c2 =~ /^\D/) { + # $c2 begins with a letter but $c1 doesn't. Let $c1 + # win the comparison, as above. + return 1; + } + else { + # Neither component begins with a leading letter. + # Check for numeric inequality. We assume here that (for example) + # "3.09" < "3.10", and that we aren't going to be asked to + # decide between "3.010" and "3.10". + if ($c1 != $c2) { + return $c1 <=> $c2; + } + # String comparison, given numeric equality. This + # handles comparisons of the form "3.4j" < "3.4k". This form + # technically isn't allowed by the Porter's Handbook, but a + # number of ports in the FreeBSD Ports Collection as of this + # writing use it (graphics/jpeg and graphics/xv). So we need + # to support it. + else { + return $c1 cmp $c2; + } + } + } } # *************** *** 194,203 **** # sub PrintHelp { print <<"EOF" ! pkg_version $Version ! Bruce A. Mah ! ! Usage: pkg_version [-c] [-d debug] [-h] [-v] [index] -c Show commands to update installed packages -d debug Debugging output (debug controls level of output) -h Help (this message) --- 254,261 ---- # sub PrintHelp { print <<"EOF" ! Usage: pkg_version [-c] [-d debug] [-h] [-l limchar] [-L limchar] [-v] [index] ! pkg_version [-d debug] -t v1 v2 -c Show commands to update installed packages -d debug Debugging output (debug controls level of output) -h Help (this message) *************** *** 206,218 **** -v Verbose output index URL or filename of index file (Default is $IndexFile) EOF } # # Parse command-line arguments, deal with them # ! if (!getopts('cdhl:L:v') || ($opt_h)) { &PrintHelp(); exit; } --- 264,278 ---- -v Verbose output index URL or filename of index file (Default is $IndexFile) + + -t v1 v2 Test two version strings EOF } # # Parse command-line arguments, deal with them # ! if (!getopts('cdhl:L:tv') || ($opt_h)) { &PrintHelp(); exit; } *************** *** 231,241 **** if ($opt_L) { $PreventFlag = $opt_L; } if ($opt_v) { $VerboseFlag = 1; } if ($#ARGV >= 0) { ! $IndexFile = $ARGV[0]; } # Determine what command to use to retrieve the index file. --- 291,324 ---- if ($opt_L) { $PreventFlag = $opt_L; } + if ($opt_t) { + $TestFlag = 1; + } if ($opt_v) { $VerboseFlag = 1; } if ($#ARGV >= 0) { ! if ($TestFlag) { ! ($test1, $test2) = @ARGV; ! } ! else { ! $IndexFile = $ARGV[0]; ! } ! } ! ! # Handle test flag now ! if ($TestFlag) { ! my $cmp = CompareVersions($test1, $test2); ! if ($cmp < 0) { ! print "<\n"; ! } ! elsif ($cmp == 0) { ! print "=\n"; ! } ! else { ! print ">\n"; ! } ! exit(0); } # Determine what command to use to retrieve the index file. --==_Exmh_-1096974478P Content-Type: application/pgp-signature -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.0.4 (FreeBSD) Comment: Exmh version 2.2 06/23/2000 iD8DBQE6wU5q2MoxcVugUsMRAnScAKDZ6rqKkqhyjig+PVq7sICiIhjVKwCgg6bv PHb4nZnOjfE+CvvVciIrRUg= =FR6a -----END PGP SIGNATURE----- --==_Exmh_-1096974478P-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-ports" in the body of the message