From d6adb0abe1288c3950bc7db8b92c816de4b77431 Mon Sep 17 00:00:00 2001 From: cjwatson <> Date: Sun, 17 Jul 2005 15:06:26 -0800 Subject: [PATCH] [project @ 2005-07-17 16:06:26 by cjwatson] Land branch-2_4_1-version-tracking. --- Debbugs/Versions.pm | 18 ++- cgi/bugreport.cgi | 2 +- cgi/common.pl | 213 +++++++++++++++++++++++++++++------ cgi/pkgreport.cgi | 9 +- migrate/debbugs-makeversions | 79 ++++++++----- scripts/errorlib.in | 73 +++++++++++- scripts/process.in | 48 +++++--- scripts/service.in | 64 ++++++++++- 8 files changed, 415 insertions(+), 91 deletions(-) diff --git a/Debbugs/Versions.pm b/Debbugs/Versions.pm index 3da63ce2..a5c697a2 100644 --- a/Debbugs/Versions.pm +++ b/Debbugs/Versions.pm @@ -157,7 +157,13 @@ sub save ($*) for my $v (@vers) { delete $leaf{$parent->{$v}} if defined $parent->{$v}; } - my @leaves = reverse sort { $self->{vercmp}->($a, $b) } keys %leaf; + # TODO: breaks with tcp-wrappers/1.0-1 tcpd/2.0-1 case + my @leaves = reverse sort { + my ($x, $y) = ($a, $b); + $x =~ s{.*/}{}; + $y =~ s{.*/}{}; + $self->{vercmp}->($x, $y); + } keys %leaf; my %seen; for my $lf (@leaves) { @@ -207,6 +213,16 @@ sub buggy ($$$$) return 'fixed' if $fixed{$node}; } + unless (@$found) { + # We don't know when it was found. Was it fixed in a descendant of + # this version? If so, this one should be considered buggy. + for my $f (@$fixed) { + for (my $node = $f; defined $node; $node = $parent->{$node}) { + return 'found' if $node eq $version; + } + } + } + # Nothing in the requested version's ancestor chain can be confirmed as # a version in which the bug was found or fixed. If it was only found or # fixed on some other branch, then this one isn't buggy. diff --git a/cgi/bugreport.cgi b/cgi/bugreport.cgi index f46cad8c..2514b6d7 100755 --- a/cgi/bugreport.cgi +++ b/cgi/bugreport.cgi @@ -180,7 +180,7 @@ if ($status{severity} eq 'normal') { } $indexentry .= "
$showseverity";
-$indexentry .= htmlpackagelinks($status{package}, 0);
+$indexentry .= htmlpackagelinks($status{package}, 0) . ";\n";
$indexentry .= htmladdresslinks("Reported by: ", \&submitterurl,
$status{originator}) . ";\n";
diff --git a/cgi/common.pl b/cgi/common.pl
index 74da3c45..6032390b 100644
--- a/cgi/common.pl
+++ b/cgi/common.pl
@@ -243,7 +243,7 @@ sub htmlpackagelinks {
'' .
$openstrong . htmlsanit($_) . $closestrong . ''
} @pkglist
- ) . ";\n";
+ );
}
# Generate a comma-separated list of HTML links to each address given in
@@ -296,6 +296,25 @@ sub htmlindexentrystatus {
}
$result .= htmlpackagelinks($status{"package"}, 1);
+
+ my $showversions = '';
+ if (@{$status{found_versions}}) {
+ my @found = @{$status{found_versions}};
+ local $_;
+ s{/}{ } foreach @found;
+ $showversions .= join ', ', map htmlsanit($_), @found;
+ }
+ if (@{$status{fixed_versions}}) {
+ $showversions .= '; ' if length $showversions;
+ $showversions .= 'fixed: ';
+ my @fixed = @{$status{fixed_versions}};
+ local $_;
+ s{/}{ } foreach @fixed;
+ $showversions .= join ', ', map htmlsanit($_), @fixed;
+ }
+ $result .= " ($showversions)" if length $showversions;
+ $result .= ";\n";
+
$result .= $showseverity;
$result .= htmladdresslinks("Reported by: ", \&submitterurl,
$status{originator});
@@ -313,22 +332,7 @@ sub htmlindexentrystatus {
$mseparator= ", ";
}
- if (@{$status{found_versions}}) {
- $result .= ";\nfound in ";
- $result .= (@{$status{found_versions}} == 1) ? 'version '
- : 'versions ';
- $result .= join ', ', map htmlsanit($_), @{$status{found_versions}};
- }
-
- if (@{$status{fixed_versions}}) {
- $result .= ";\nfixed in ";
- $result .= (@{$status{fixed_versions}} == 1) ? 'version '
- : 'versions ';
- $result .= join ', ', map htmlsanit($_), @{$status{fixed_versions}};
- if (length($status{done})) {
- $result .= ' by ' . htmlsanit($status{done});
- }
- } elsif (length($status{done})) {
+ if (length($status{done})) {
$result .= ";\nDone: " . htmlsanit($status{done});
$days = ceil($debbugs::gRemoveAge - -M buglog($status{id}));
if ($days >= 0) {
@@ -811,24 +815,40 @@ sub getbugstatus {
$status{"pending"} = 'pending-fixed' if ($tags{pending});
$status{"pending"} = 'fixed' if ($tags{fixed});
- my $version;
+ my @versions;
if (defined $common_version) {
- $version = $common_version;
+ @versions = ($common_version);
} elsif (defined $common_dist) {
- $version = getversion($status{package}, $common_dist, $common_arch);
+ @versions = getversions($status{package}, $common_dist, $common_arch);
}
- if (defined $version) {
- my $buggy = buggyversion($bugnum, $version, \%status);
- if ($buggy eq 'absent') {
+ # TODO: This should probably be handled further out for efficiency and
+ # for more ease of distinguishing between pkg= and src= queries.
+ my @sourceversions = makesourceversions($status{package}, $common_arch,
+ @versions);
+
+ if (@sourceversions) {
+ # Resolve bugginess states (we might be looking at multiple
+ # architectures, say). Found wins, then fixed, then absent.
+ my $maxbuggy = 'absent';
+ for my $version (@sourceversions) {
+ my $buggy = buggyversion($bugnum, $version, \%status);
+ if ($buggy eq 'found') {
+ $maxbuggy = 'found';
+ last;
+ } elsif ($buggy eq 'fixed' and $maxbuggy ne 'found') {
+ $maxbuggy = 'fixed';
+ }
+ }
+ if ($maxbuggy eq 'absent') {
$status{"pending"} = 'absent';
- } elsif ($buggy eq 'fixed') {
+ } elsif ($maxbuggy eq 'fixed') {
$status{"pending"} = 'done';
}
}
if (length($status{done}) and
- (not defined $version or not @{$status{fixed_versions}})) {
+ (not @sourceversions or not @{$status{fixed_versions}})) {
$status{"pending"} = 'done';
}
@@ -854,6 +874,29 @@ sub buglog {
return getbugcomponent($bugnum, 'log.gz', $location);
}
+# Canonicalize versions into source versions, which have an explicitly
+# named source package. This is used to cope with source packages whose
+# names have changed during their history, and with cases where source
+# version numbers differ from binary version numbers.
+sub makesourceversions {
+ my $pkg = shift;
+ my $arch = shift;
+ my %sourceversions;
+
+ for my $version (@_) {
+ if ($version =~ m[/]) {
+ # Already a source version.
+ $sourceversions{$version} = 1;
+ } else {
+ my @srcinfo = binarytosource($pkg, $version, $arch);
+ next unless @srcinfo;
+ $sourceversions{"$_->[0]/$_->[1]"} = 1 foreach @srcinfo;
+ }
+ }
+
+ return sort keys %sourceversions;
+}
+
my %_versionobj;
sub buggyversion {
my ($bug, $ver, $status) = @_;
@@ -866,30 +909,136 @@ sub buggyversion {
$tree = $_versionobj{$src};
} else {
$tree = Debbugs::Versions->new(\&DpkgVer::vercmp);
- if (open VERFILE, "< $gVersionPackagesDir/$src") {
+ my $srchash = substr $src, 0, 1;
+ if (open VERFILE, "< $gVersionPackagesDir/$srchash/$src") {
$tree->load(\*VERFILE);
close VERFILE;
}
$_versionobj{$src} = $tree;
}
- return $tree->buggy($ver, $status->{found_versions},
- $status->{fixed_versions});
+ my @found = makesourceversions($status->{package}, undef,
+ @{$status->{found_versions}});
+ my @fixed = makesourceversions($status->{package}, undef,
+ @{$status->{fixed_versions}});
+
+ return $tree->buggy($ver, \@found, \@fixed);
}
my %_versions;
-sub getversion {
+sub getversions {
my ($pkg, $dist, $arch) = @_;
- return undef unless defined $gVersionIndex;
+ return () unless defined $gVersionIndex;
$dist = 'unstable' unless defined $dist;
- $arch = 'i386' unless defined $arch;
unless (tied %_versions) {
tie %_versions, 'MLDBM', $gVersionIndex, O_RDONLY
or die "can't open versions index: $!";
}
- return $_versions{$pkg}{$dist}{$arch};
+ if (defined $arch) {
+ my $ver = $_versions{$pkg}{$dist}{$arch};
+ return $ver if defined $ver;
+ return ();
+ } else {
+ my %uniq;
+ for my $ar (keys %{$_versions{$pkg}{$dist}}) {
+ $uniq{$_versions{$pkg}{$dist}{$ar}} = 1 unless $ar eq 'source';
+ }
+ return keys %uniq;
+ }
+}
+
+sub getversiondesc {
+ my $pkg = shift;
+
+ if (defined $common_version) {
+ return "version $common_version";
+ } elsif (defined $common_dist) {
+ my @distvers = getversions($pkg, $common_dist, $common_arch);
+ @distvers = sort @distvers;
+ local $" = ', ';
+ if (@distvers > 1) {
+ return "versions @distvers";
+ } elsif (@distvers == 1) {
+ return "version @distvers";
+ }
+ }
+
+ return undef;
+}
+
+# Returns an array of zero or more references to (srcname, srcver) pairs.
+# If $binarch is undef, returns results for all architectures.
+my %_binarytosource;
+sub binarytosource {
+ my ($binname, $binver, $binarch) = @_;
+
+ # TODO: This gets hit a lot, especially from buggyversion() - probably
+ # need an extra cache for speed here.
+
+ if (tied %_binarytosource or
+ tie %_binarytosource, 'MLDBM', $gBinarySourceMap, O_RDONLY) {
+ # avoid autovivification
+ if (exists $_binarytosource{$binname} and
+ exists $_binarytosource{$binname}{$binver}) {
+ if (defined $binarch) {
+ my $src = $_binarytosource{$binname}{$binver}{$binarch};
+ return () unless defined $src; # not on this arch
+ # Copy the data to avoid tiedness problems.
+ return [@$src];
+ } else {
+ # Get (srcname, srcver) pairs for all architectures and
+ # remove any duplicates. This involves some slightly tricky
+ # multidimensional hashing; sorry. Fortunately there'll
+ # usually only be one pair returned.
+ my %uniq;
+ for my $ar (keys %{$_binarytosource{$binname}{$binver}}) {
+ my $src = $_binarytosource{$binname}{$binver}{$ar};
+ next unless defined $src;
+ $uniq{$src->[0]}{$src->[1]} = 1;
+ }
+ my @uniq;
+ for my $sn (sort keys %uniq) {
+ push @uniq, [$sn, $_] for sort keys %{$uniq{$sn}};
+ }
+ return @uniq;
+ }
+ }
+ }
+
+ # No $gBinarySourceMap, or it didn't have an entry for this name and
+ # version. Try $gPackageSource (unversioned) instead.
+ my $pkgsrc = getpkgsrc();
+ if (exists $pkgsrc->{$binname}) {
+ return [$pkgsrc->{$binname}, $binver];
+ } else {
+ return ();
+ }
+}
+
+# Returns an array of zero or more references to
+# (binname, binver[, binarch]) triplets.
+my %_sourcetobinary;
+sub sourcetobinary {
+ my ($srcname, $srcver) = @_;
+
+ if (tied %_sourcetobinary or
+ tie %_sourcetobinary, 'MLDBM', $gSourceBinaryMap, O_RDONLY) {
+ # avoid autovivification
+ if (exists $_sourcetobinary{$srcname} and
+ exists $_sourcetobinary{$srcname}{$srcver}) {
+ my $bin = $_sourcetobinary{$srcname}{$srcver};
+ return () unless defined $bin;
+ # Copy the data to avoid tiedness problems.
+ return @$bin;
+ }
+ }
+
+ # No $gSourceBinaryMap, or it didn't have an entry for this name and
+ # version. Try $gPackageSource (unversioned) instead.
+ my @srcpkgs = getsrcpkgs($srcname);
+ return map [$_, $srcver], @srcpkgs;
}
1;
diff --git a/cgi/pkgreport.cgi b/cgi/pkgreport.cgi
index f8b32424..74bf6065 100755
--- a/cgi/pkgreport.cgi
+++ b/cgi/pkgreport.cgi
@@ -125,8 +125,8 @@ if (defined $pkg) {
$title .= " (version $version)";
} elsif (defined $dist) {
$title .= " in $dist";
- my $distver = getversion($pkg, $dist, $arch);
- $title .= " (version $distver)" if defined $distver;
+ my $verdesc = getversiondesc($pkg);
+ $title .= " ($verdesc)" if defined $verdesc;
}
my @pkgs = split /,/, $pkg;
@bugs = @{getbugs(sub {my %d=@_;
@@ -137,12 +137,13 @@ if (defined $pkg) {
}, 'package', @pkgs)};
} elsif (defined $src) {
$title = "source $src";
+ set_option('arch', 'source');
if (defined $version) {
$title .= " (version $version)";
} elsif (defined $dist) {
$title .= " in $dist";
- my $distver = getversion($src, $dist, 'source');
- $title .= " (version $distver)" if defined $distver;
+ my $verdesc = getversiondesc($src);
+ $title .= " ($verdesc)" if defined $verdesc;
}
my @pkgs = ();
my @srcs = split /,/, $src;
diff --git a/migrate/debbugs-makeversions b/migrate/debbugs-makeversions
index dfc565b7..234d0fdb 100755
--- a/migrate/debbugs-makeversions
+++ b/migrate/debbugs-makeversions
@@ -18,7 +18,6 @@ EOF
sub getbuginfo ($)
{
my $log = shift;
- print "Processing $log ...\n";
open LOG, "< $log" or die "Can't open $log: $!";
my @records = read_log_records(*LOG);
@@ -56,27 +55,46 @@ sub getbuginfo ($)
# Get Version: pseudo-headers.
my $i;
+ my ($source, $sourcever, $ver);
for ($i = 0; $i < @{$decoded->{body}}; ++$i) {
last if $decoded->{body}[$i] !~ /^(\S+):\s*(.*)/;
my ($fn, $fv) = (lc $1, $2);
- next if $fn ne 'version';
- next if $fv !~ /^(\d[^,\s]*(?:[,\s]+|$))+/;
- if ($closing) {
- for my $v (split /[,\s]+/, $fv) {
- push @fixed_versions, $v
- unless exists $fixed_versions{$v};
- $fixed_versions{$v} = 1;
- @found_versions = grep { $_ ne $v } @found_versions;
- delete $found_versions{$v};
- }
- } else {
- for my $v (split /[,\s]+/, $fv) {
- push @found_versions, $v
- unless exists $found_versions{$v};
- $found_versions{$v} = 1;
- @fixed_versions = grep { $_ ne $v } @fixed_versions;
- delete $fixed_versions{$v};
- }
+ if ($fn eq 'source') {
+ $source = $fv;
+ } elsif ($fn eq 'source-version' and
+ $fv =~ /^(\d[^,\s]*(?:[,\s]+|$))+/) {
+ $sourcever = $fv;
+ } elsif ($fn eq 'version' and $fv =~ /^(\d[^,\s]*(?:[,\s]+|$))+/) {
+ # Deal with reportbug brain-damage.
+ next if $fv =~ /^unavailable/i;
+ $fv =~ s/;.*//;
+ $fv =~ s/ *\(.*\)//;
+ $ver = $fv;
+ }
+ }
+
+ my @parsedvers;
+ if (defined $ver) {
+ push @parsedvers, split /[,\s]+/, $ver;
+ } elsif (defined $source and defined $sourcever) {
+ push @parsedvers, map "$source/$_", split /[,\s]+/, $sourcever;
+ }
+
+ if ($closing) {
+ for my $v (@parsedvers) {
+ push @fixed_versions, $v
+ unless exists $fixed_versions{$v};
+ $fixed_versions{$v} = 1;
+ @found_versions = grep { $_ ne $v } @found_versions;
+ delete $found_versions{$v};
+ }
+ } else {
+ for my $v (@parsedvers) {
+ push @found_versions, $v
+ unless exists $found_versions{$v};
+ $found_versions{$v} = 1;
+ @fixed_versions = grep { $_ ne $v } @fixed_versions;
+ delete $fixed_versions{$v};
}
}
@@ -84,13 +102,13 @@ sub getbuginfo ($)
# Look for Debian changelogs.
for (; $i < @{$decoded->{body}}; ++$i) {
if ($decoded->{body}[$i] =~
- /\S+ \(([^)]+)\) \S+; urgency=\S+/i) {
- my $v = $1;
- push @fixed_versions, $v
- unless exists $fixed_versions{$v};
- $fixed_versions{$v} = 1;
- @found_versions = grep { $_ ne $v } @found_versions;
- delete $found_versions{$v};
+ /(\w[-+0-9a-z.]+) \(([^\(\) \t]+)\) \S+; urgency=\S+/i) {
+ my ($p, $v) = ($1, $2);
+ push @fixed_versions, "$p/$v"
+ unless exists $fixed_versions{"$p/$v"};
+ $fixed_versions{"$p/$v"} = 1;
+ @found_versions = grep { $_ ne "$p/$v" } @found_versions;
+ delete $found_versions{"$p/$v"};
last;
}
}
@@ -128,9 +146,12 @@ while (defined(my $dir = readdir DB)) {
$bug =~ /(..)$/;
my $bughash = $1;
- next if -e "$verdb/$bughash/$bug.versions" and
- (stat "$verdb/$bughash/$bug.versions")[9] >=
- (stat "$db/$dir/$file")[9];
+ # For incremental updates.
+ #next if -e "$verdb/$bughash/$bug.versions" and
+ # (stat "$verdb/$bughash/$bug.versions")[9] >=
+ # (stat "$db/$dir/$file")[9];
+
+ print "Processing $bug ...\n" if $ENV{DEBBUGS_VERBOSE};
open STATUS, "$db/$dir/$bug.status" or next;
.nn
# Temps: incoming/P
.nn
@@ -242,16 +242,21 @@ END
last;
}
#### interesting ones start here
- } elsif (m/^close\s+\#?(-?\d+)$/i) {
+ } elsif (m/^close\s+\#?(-?\d+)(?:\s+(\d.*))?$/i) {
$ok++;
$ref= $1;
+ $version= $2;
if (&setbug) {
&transcript("'close' is deprecated; see http://$gWebDomain/Developer$gHTMLSuffix#closing.\n");
- if (length($data->{done})) {
+ if (length($data->{done}) and not defined($version)) {
&transcript("$gBug is already closed, cannot re-close.\n\n");
&nochangebug;
} else {
- $action= "$gBug closed, send any further explanations to $data->{originator}";
+ $action= "$gBug " .
+ (defined($version) ?
+ "marked as fixed in version $version" :
+ "closed") .
+ ", send any further explanations to $data->{originator}";
do {
&addmaintainers($data);
if ( length( $gDoneList ) > 0 && length( $gListDomain ) >
@@ -263,6 +268,7 @@ END
$data->{keywords}= join ' ', grep $_ ne 'pending',
@keywords;
}
+ addfixedversions($data, undef, $version);
$message= <