Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 27 Sep 2000 06:15:39 +0900
From:      "Akinori -Aki- MUSHA" <knu@idaemons.org>
To:        freebsd-ports@FreeBSD.org
Cc:        bmah@FreeBSD.org
Subject:   Enhancement of pkg_version's version comparison routine
Message-ID:  <86k8by6eis.wl@archon.local.idaemons.org>

next in thread | raw e-mail | index | archive | help
Hi Bruce and Ports,

I made a patch that fixes pkg_version's version comparison routine.
In short, it makes pkg_version recognize alpha ("a"), beta ("b"),
pre ("p"), and patchlevels as the handbook says.

With this fix, comparisons will result as the following:

Winer       Loser       Comment
1.6.0       1.6.0.p3    Pre is before the release (*)
1.0.b       1.0.a3      Beta is after alpha's
1.0a        1.0         A letter "a" means alpha only when it appears
                        after an period.
5.0a        5.0.b       Ditto.
3.2.ab1     3.2.p1      "ab" is unknown, but at least it should be
                        after alpha's, beta's and pre's. (*)
2.3pl10     2.3pl9      Patchlevel 10 is after 9, of course (*)

where (*) indicates previously it wasn't handled correctly.


To perform comparison from scripts, I also implemented `-t' option so
you can use it like this:

	#!/bin/sh
	version=$(cd /var/db/pkg; echo foobar-* | sed -e 's/.*-//' -e 's/[_,].*//')
	if pkg_version -t "${version} < 1.5.b5"; then
		echo "You need foobar version 1.5 beta5 or later installed."
		exit 1
	fi
	exit 0

Yes, this feature can be used from such as REQ scripts when you need
to compare package versions. (until we get more sophisticated pkg_*
tools/framework :)


Bruce, would you review and approve this change?

-- 
                           /
                          /__  __       
                         / )  )  ) )  /
Akinori -Aki- MUSHA aka / (_ /  ( (__(  @ idaemons.org / FreeBSD.org

"We're only at home when we're on the run, on the wing, on the fly"

Index: pkg_version.1
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pkg_install/version/pkg_version.1,v
retrieving revision 1.8
diff -u -r1.8 pkg_version.1
--- pkg_version.1	2000/09/15 04:16:20	1.8
+++ pkg_version.1	2000/09/26 20:23:39
@@ -35,6 +35,8 @@
 .Op Fl cdhv
 .Op Fl l Ar limchar
 .Op Ar index
+.Nm pkg_version
+.Op Fl t Ar expression
 .Sh DESCRIPTION
 The
 .Nm
@@ -93,6 +95,44 @@
 to the shell, it is best to quote
 .Ar limchar
 with single quotes.
+.It Fl t 
+Test an expression and exit.  It returns either 0 (true) or 1 (false).
+.It Ar expression
+Specify the expression to test, in one of the following forms:
+.Bl -tag -width Ar
+.It Ar \&v\&1 Cm \&= Ar \&v\&2
+True if the versions
+.Ar \&v\&1
+and
+.Ar \&v\&2
+are identical.
+.It Ar \&v\&1 Cm \&!= Ar \&v\&2
+True if the versions
+.Ar \&v\&1
+and
+.Ar \&v\&2
+are not identical.
+.It Ar \&v\&1 Cm \&< Ar \&v\&2
+True if the version
+.Ar \&v\&1
+is less than the version
+.Ar \&v\&2 .
+.It Ar \&v\&1 Cm \&> Ar \&v\&2
+True if the version
+.Ar \&v\&1
+is greater than the version
+.Ar \&v\&2 .
+.It Ar \&v\&1 Cm \&<= Ar \&v\&2
+True if the version
+.Ar \&v\&1
+is less than or equal to the version
+.Ar \&v\&2 .
+.It Ar \&v\&1 Cm \&>= Ar \&v\&2
+True if the version
+.Ar \&v\&1
+is greater than or equal to the version
+.Ar \&v\&2 .
+.El
 .It Fl v
 Enable verbose output.  Verbose output includes some English-text
 interpretations of the version number comparisons, as well as the
@@ -144,18 +184,20 @@
 suggestions, and then cut-and-paste (or retype) the commands you want to run.
 .Pp
 .Dl % pkg_version -c > do_update
+.Pp
+The following command tests if a version is less than another.
+.Pp
+.Dl % pkg_version -t '1.6.0.p3 < 1.6.0' && echo 'true!'
 .Sh AUTHOR
 .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 Mark Ovens Aq marko@FreeBSD.org ,
+.An Akinori MUSHA Aq knu@FreeBSD.org
 .Sh BUGS
 There should be a better way of dealing with packages that
 can have more than one installed version.
-.Pp
-Patch levels aren't handled
-very well (i.e. version numbers of the form 1.2p3 or 1.2pl3).
 .Pp
 Updates to packages
 that don't change the version number (e.g. small delta bugfixes in the
Index: pkg_version.pl
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pkg_install/version/pkg_version.pl,v
retrieving revision 1.10
diff -u -r1.10 pkg_version.pl
--- pkg_version.pl	2000/09/15 04:16:20	1.10
+++ pkg_version.pl	2000/09/26 19:55:09
@@ -57,38 +57,87 @@
 # This function returns -1, 0, or 1, in the same manner as <=> or cmp.
 #
 sub CompareNumbers {
-    local($v1, $v2);
-    $v1 = $_[0];
-    $v2 = $_[1];
+    my($v1, $v2) = @_;
 
     # Short-cut in case of equality
     if ($v1 eq $v2) {
 	return 0;
     }
 
-    # 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;
+    # Split into subnumbers
+    my @s1 = split(/\./, $v1);
+    my @s2 = split(/\./, $v2);
+
+    # Subnumbers
+    my($s1, $s2);
+
+    # Seek for the difference
+    do {
+	last unless @s1 || @s2;
+
+	$s1 = shift @s1;
+	$s2 = shift @s2;
+    } while ($s1 eq $s2);
+
+    # Short-cut in case of equality
+    if ($s1 eq $s2) {
+	return 0;
+    }
+
+    # Split into sub-subnumbers
+    my @x1 = split(/(\D+)/, $s1);
+    my @x2 = split(/(\D+)/, $s2);
+
+    shift @x1 if ($s1 =~ /^\D/);
+    shift @x2 if ($s2 =~ /^\D/);
+
+    # Sub-subnumbers
+    my $x1 = shift @x1;
+    my $x2 = shift @x2;
+
+    # Check for alpha, beta, or pre
+    if ($x1 =~ /^[abp]$/) {
+	if ($x2 !~ /^[abp]$/) {
+	    return -1;		# A non-abp (including null) wins over an abp
 	}
-	# Check for numeric inequality.  We assume here that (for example)
-	# 3.09 < 3.10.
-	elsif ($p1 != $p2) {
-	    return $p1 <=> $p2;
+
+	if ($x1 ne $x2) {
+	    return $x1 cmp $x2;	# Accidentally, 'a' < 'b' < 'p' :)
 	}
-	# 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;
+    } elsif ($x2 =~ /^[abp]$/) {
+	return 1;		# A non-abp (including null) wins over an abp
+    }
+
+    # Seek for the difference
+    while ($x1 eq $x2) {
+	last unless @x1 || @x2;
+
+	$x1 = shift @x1;
+	$x2 = shift @x2;
+    }
+
+    # Short-cut in case of equality
+    if ($x1 eq $x2) {
+	return 0;
+    }
+
+    if ($x1 =~ /^\d/) {
+	if ($x2 =~ /^\d/) {
+	    # Both numbers: compare numerically
+	    return $x1 <=> $x2;
 	}
+
+	# A number wins over non-numbers
+	return 1;
     }
 
+    if ($x2 =~ /^\d/) {
+	# A number wins over non-numbers
+	return -1;
+    }
+
+    # Both non-numbers: compare as strings
+    return $x1 cmp $x2;
 }
 
 #
@@ -197,6 +246,7 @@
 -d debug	Debugging output (debug controls level of output)
 -h		Help (this message)
 -l limchar	Limit output
+-t expr		Test expression
 -v		Verbose output
 index		URL or filename of index file
 		(Default is $IndexFile)
@@ -206,7 +256,7 @@
 #
 # Parse command-line arguments, deal with them
 #
-if (!getopts('cdhl:v') || ($opt_h)) {
+if (!getopts('cdhl:t:v') || ($opt_h)) {
     &PrintHelp();
     exit;
 }
@@ -218,6 +268,34 @@
 }
 if ($opt_l) {
     $LimitFlag = $opt_l;
+}
+if ($opt_t) {
+    my $expr = $opt_t;
+
+    $expr =~ s/\s+//g;
+
+    my($v1, $op, $v2) = split(/([<>]=?|=|!=|)/, $expr, 2);
+
+    if ($v2 eq '') {
+	print "Invalid expression: $expr\n";
+	exit -1;
+    }
+
+    my $cmp = CompareVersions($v1, $v2);
+
+    if ($op =~ /</) {
+	exit($cmp < 0);
+    }
+
+    if ($op =~ />/) {
+	exit($cmp > 0);
+    }
+
+    if ($op =~ /!/) {
+	exit($cmp != 0);
+    }
+
+    exit($cmp == 0);
 }
 if ($opt_v) {
     $VerboseFlag = 1;


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-ports" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?86k8by6eis.wl>