]> git.donarmstrong.com Git - debbugs.git/blob - migrate/debbugs-makeversions
[project @ 2005-07-17 18:09:40 by cjwatson]
[debbugs.git] / migrate / debbugs-makeversions
1 #! /usr/bin/perl -w
2 # Extract version information from an existing non-versioned database by
3 # guesswork, based on Version: pseudo-headers and closing mails that look
4 # like Debian changelogs. The latter in particular is somewhat heuristic.
5
6 my $config_path = '/etc/debbugs';
7 my $lib_path = '/usr/lib/debbugs';
8
9 require "$config_path/config";
10 require "$lib_path/errorlib";
11
12 use Debbugs::Log;
13 use Debbugs::MIME;
14
15 if (@ARGV != 1) {
16     print <<EOF;
17 Usage: $0 db-type
18
19 EOF
20     exit 0;
21 }
22
23 sub getbuginfo ($)
24 {
25     my $log = shift;
26
27     open LOG, "< $log" or die "Can't open $log: $!";
28     my @records = read_log_records(*LOG);
29     close LOG;
30
31     my (@found_versions, @fixed_versions);
32     my (%found_versions, %fixed_versions);
33
34     for my $record (@records) {
35         if ($record->{type} eq 'html') {
36             # Reassigns zap the found and fixed version list. Reopens will
37             # zap the fixed list too in the full deployment, but doing that
38             # here causes problems in case of accidental reopens and
39             # recloses.
40             if ($record->{text} =~ /assigned/) {
41                 @found_versions = ();
42                 %found_versions = ();
43                 @fixed_versions = ();
44                 %fixed_versions = ();
45             }
46             next;
47         }
48
49         next unless $record->{type} eq 'autocheck' or
50                     $record->{type} eq 'incoming-recv';
51         my $decoded = Debbugs::MIME::parse($record->{text});
52         next unless defined $decoded;
53
54         # Was it sent to -done or -close?
55         my $closing = 0;
56         my $firstreceived = $decoded->{header}[0];
57         if ($firstreceived =~ /\(at [^)]*-(?:done|close)\)/) {
58             $closing = 1;
59         }
60
61         # Get Version: pseudo-headers.
62         my $i;
63         my ($source, $sourcever, $ver);
64         for ($i = 0; $i < @{$decoded->{body}}; ++$i) {
65             last if $decoded->{body}[$i] !~ /^(\S+):\s*(.*)/;
66             my ($fn, $fv) = (lc $1, $2);
67             if ($fn eq 'source') {
68                 $source = $fv;
69             } elsif ($fn eq 'source-version' and
70                      $fv =~ /^(\d[^,\s]*(?:[,\s]+|$))+/) {
71                 $sourcever = $fv;
72             } elsif ($fn eq 'version' and $fv =~ /^(\d[^,\s]*(?:[,\s]+|$))+/) {
73                 # Deal with reportbug brain-damage.
74                 next if $fv =~ /^unavailable/i;
75                 $fv =~ s/;.*//;
76                 $fv =~ s/ *\(.*\)//;
77                 # Strip off other random junk at the end of a version.
78                 $fv =~ s/ *[A-Za-z].*//;
79                 $ver = $fv;
80             }
81         }
82
83         my @parsedvers;
84         if (defined $ver) {
85             push @parsedvers, split /[,\s]+/, $ver;
86         } elsif (defined $source and defined $sourcever) {
87             push @parsedvers, map "$source/$_", split /[,\s]+/, $sourcever;
88         }
89
90         if ($closing) {
91             for my $v (@parsedvers) {
92                 push @fixed_versions, $v
93                     unless exists $fixed_versions{$v};
94                 $fixed_versions{$v} = 1;
95                 @found_versions = grep { $_ ne $v } @found_versions;
96                 delete $found_versions{$v};
97             }
98         } else {
99             for my $v (@parsedvers) {
100                 push @found_versions, $v
101                     unless exists $found_versions{$v};
102                 $found_versions{$v} = 1;
103                 @fixed_versions = grep { $_ ne $v } @fixed_versions;
104                 delete $fixed_versions{$v};
105             }
106         }
107
108         if ($closing) {
109             # Look for Debian changelogs.
110             for (; $i < @{$decoded->{body}}; ++$i) {
111                 if ($decoded->{body}[$i] =~
112                         /(\w[-+0-9a-z.]+) \(([^\(\) \t]+)\) \S+; urgency=\S+/i) {
113                     my ($p, $v) = ($1, $2);
114                     push @fixed_versions, "$p/$v"
115                         unless exists $fixed_versions{"$p/$v"};
116                     $fixed_versions{"$p/$v"} = 1;
117                     @found_versions = grep { $_ ne "$p/$v" } @found_versions;
118                     delete $found_versions{"$p/$v"};
119                     last;
120                 }
121             }
122         }
123     }
124
125     return (\@found_versions, \@fixed_versions);
126 }
127
128 sub mergeinto ($$)
129 {
130     my ($target, $source) = @_;
131     my %seen = map { $_ => 1 } @$target;
132     for my $v (@$source) {
133         next if exists $seen{$v};
134         push @$target, $v;
135         $seen{$v} = 1;
136     }
137 }
138
139 chdir $gSpoolDir or die "Can't chdir $gSpoolDir: $!";
140
141 my $db = $ARGV[0];
142 opendir DB, $db or die "Can't opendir $db: $!";
143
144 while (defined(my $dir = readdir DB)) {
145     next if $dir =~ /^\.\.?$/ or not -d "$db/$dir";
146     opendir HASH, "$db/$dir" or die "Can't opendir $db/$dir: $!";
147
148     while (defined(my $file = readdir HASH)) {
149         next unless $file =~ /\.log$/;
150         next if -z "$db/$dir/$file";
151         (my $bug = $file) =~ s/\..*//;
152
153         $bug =~ /(..)$/;
154         my $bughash = $1;
155
156         print "Processing $bug ...\n" if $ENV{DEBBUGS_VERBOSE};
157
158         my ($locks, $status) = lockreadbugmerge($bug, $db);
159         unless (defined $status) {
160             unlockreadbugmerge($locks);
161             next;
162         }
163
164         my ($found_versions, $fixed_versions) = getbuginfo("$db/$dir/$file");
165
166         if (length $status->{mergedwith}) {
167             @merges = sort { $a <=> $b } split ' ', $status->{mergedwith};
168             if ($merges[0] < $bug) {
169                 # already processed
170                 unlockreadbugmerge($locks);
171                 next;
172             }
173             for my $merge (@merges) {
174                 $merge =~ /(..)$/;
175                 my $mergehash = $1;
176                 my ($mfound, $mfixed) =
177                     getbuginfo("$db/$mergehash/$merge.log");
178                 mergeinto($found_versions, $mfound);
179                 mergeinto($fixed_versions, $mfixed);
180             }
181         }
182
183         @$fixed_versions = () unless length $status->{done};
184
185         for my $out ($bug, (split ' ', $status->{mergedwith})) {
186             if ($out != $bug) {
187                 filelock("lock/$out");
188             }
189             my $outstatus = readbug($out, $db);
190             $outstatus->{found_versions} = [@$found_versions];
191             $outstatus->{fixed_versions} = [@$fixed_versions];
192             writebug($out, $outstatus, $db);
193             if ($out != $bug) {
194                 unfilelock();
195             }
196         }
197
198         unlockreadbugmerge($locks);
199     }
200
201     closedir HASH;
202 }
203
204 closedir DB;