With respect to package updates, the transitive relation OVERRIDES is
defined by the following statement:  The command "pkg_add -u" will
replace a package if and only if among all available MATCHING packages,
one OVERRIDES all others.  I'm using ALL CAPS to make formally defined
terms stand out.  I'm not cencerned with the meaning of MATCH here;
that's defined by OpenBSD::Update and not subject to change in the
current context.

Marc Espie repeatedly stated that improvement of the OVERRIDES relation
is desirable.  The pkg_add(1) manual also contains a note to that effect.

Currently, OVERRIDES (">") is defined like this:

 T-MpQvW-G >= S-NpPvV-F :<=> T-MvW-G = S-NvV-F && Q >= P

with

  S: package Stem (e.g. "mutt"),
     optionally including multi-packages suffixes
  N: version Number (e.g. "1.5.16")
 pP: official OpenBSD Patch level (e.g. "p0")
     In case this is missing, it is treated as "-1".
 vV: user Variant level (e.g. "v0")
  F: Flavor suffix (e.g. "sidebar")

and equality being defined in the obvious way.

My suggestion is to change this relation like this:

 T-MpQvW-G >= S-NpPvV-F :<=> T-M-G = S-N-F && W >= V && Q >= P

Consequently, packages will be OVERRIDDEN if stem, version and flavors
agree and if either the official or the private patch level have
increased, unless the other patch level has decreased.  If "p0v1" and
"p1v0" are available but "p1v1" is not, this will be regarded as an
ambiguity.  It is not obvious whether the user will regard the latest
offical patch or the latest private changes as more important.

This is a first, non-intrusive step to improve OVERRIDE handling.  It
is not yet changing OVERRIDES among official packages, but it is only
improving the handling of user defined variants.  It is non-intrusive
also in the sense that it does not yet require UpdateInfo inspection but
can be done by looking at the package name only.  Of course and as
before, this still requires that patches with the same "S-N-F" ought to
MATCH in the sense of OpenBSD::Update.  Thus, this can be done in
OpenBSD::PackageName::keep_most_recent without touching OpenBSD::Update.
In particular, it should have very little performance implications.

The patch included below is also available from
  http://www.studis.de/Software/pkg_add-vnum-v0.patch

For further improvement, it will probably be necessary to record
additional information into the packages at pkg_create time and to
inspect the UpdateInfo contained in the packages at pkg_add time,
requiring at least partial package extraction and requiring part of
the logic to go into OpenBSD::Update.  I didn't try to do any such
thing yet.


Index: PackageName.pm
===================================================================
RCS file: /cvs/src/usr.sbin/pkg_add/OpenBSD/PackageName.pm,v
retrieving revision 1.31
diff -u -p -r1.31 PackageName.pm
--- PackageName.pm      23 Aug 2007 09:09:16 -0000      1.31
+++ PackageName.pm      29 Sep 2007 17:07:36 -0000
@@ -87,25 +87,17 @@ sub is_stem
 sub splitp
 {
        local $_ = shift;
-
-       if (/^(.*\-\d[^-]*)p(\d+)(.*)$/o) {
-               return ($1.$3, $2);
-       } else {
-               return ($_,-1);
-       }
+       m/^(.*?)(?:(\-\d.*?)(?:p(\d+))?(?:v(\d+))?(-.*)?)?$/o;
+       return  $1 . (defined $2 ? $2 : '') . (defined $5 ? $5 : ''),
+               [ (defined $3 ? $3 : -1), (defined $4 ? $4 : -1) ];
 }
 
 sub rebuildp
 {
-       my ($pkg, $p) = @_;
-       if ($p == -1) {
-               return $pkg;
-       }
-       if ($pkg =~ m/^(.*?)(\-\d[^-v]*)(.*)$/o) {
-               return "$1$2p$p$3";
-       } else {
-               return $pkg."p".$p;
-       }
+       my ($pkg, $p, $v) = ($_[0], @{$_[1]});
+       $pkg =~ m/^(.*?)(?:(\-\d.*?)(-.*)?)?$/o;
+       return  $1 . (defined $2 ? $2 : '') . ($p >= 0 ? "p$p" : '') .
+               ($v >= 0 ? "v$v" : '') . (defined $3 ? $3 : '');
 }
 
 sub keep_most_recent
@@ -113,13 +105,27 @@ sub keep_most_recent
        my $h = {};
        for my $pkgname (@_) {
                my ($p, $v) = splitp($pkgname);
-               if (!defined $h->{$p} || $h->{$p} < $v) {
-                       $h->{$p} = $v;
+               unless (defined $h->{$p}) {
+                       $h->{$p} = [ $v ];
+                       next;
+               }
+               my $nvs = [];
+               for my $ov (@{$h->{$p}}) {
+                       if ($ov->[0] >= $v->[0] && $ov->[1] >= $v->[1]) {
+                               $nvs = undef;
+                               last;
+                       } elsif ($ov->[0] > $v->[0] || $ov->[1] > $v->[1]) {
+                               push @$nvs, $ov;
+                       }
+               }
+               if (defined $nvs) {
+                       push @$nvs, $v;
+                       $h->{$p} = $nvs;
                }
        }
        my @list = ();
        while (my ($p, $v) = each %$h) {
-               push(@list, rebuildp($p, $v));
+               push @list, map(rebuildp($p, $_), @$v);
        }
        return @list;
 }

Reply via email to