]> git.donarmstrong.com Git - debbugs.git/blob - cgi/pkgreport.cgi
* pass dist on like it should be
[debbugs.git] / cgi / pkgreport.cgi
1 #!/usr/bin/perl -wT
2 # This script is part of debbugs, and is released
3 # under the terms of the GPL version 2, or any later
4 # version at your option.
5 # See the file README and COPYING for more information.
6 #
7 # [Other people have contributed to this file; their copyrights should
8 # go here too.]
9 # Copyright 2004-2006 by Anthony Towns <ajt@debian.org>
10 # Copyright 2007 by Don Armstrong <don@donarmstrong.com>.
11
12
13 use warnings;
14 use strict;
15
16 use POSIX qw(strftime nice);
17
18 use Debbugs::Config qw(:globals :text :config);
19
20 use Debbugs::User;
21
22 use Debbugs::Common qw(getparsedaddrs make_list getmaintainers getpseudodesc);
23
24 use Debbugs::Bugs qw(get_bugs bug_filter newest_bug);
25 use Debbugs::Packages qw(getsrcpkgs getpkgsrc get_versions);
26
27 use Debbugs::CGI qw(:all);
28
29 use Debbugs::CGI::Pkgreport qw(:all);
30
31 use Debbugs::Text qw(:templates);
32
33 use CGI::Simple;
34 my $q = new CGI::Simple;
35
36 if ($q->request_method() eq 'HEAD') {
37      print $q->header(-type => "text/html",
38                       -charset => 'utf-8',
39                      );
40      exit 0;
41 }
42
43 my $default_params = {ordering => 'normal',
44                       archive  => 0,
45                       repeatmerged => 0,
46                       include      => [],
47                       exclude      => [],
48                      };
49
50 our %param = cgi_parameters(query => $q,
51                             single => [qw(ordering archive repeatmerged),
52                                        qw(bug-rev pend-rev sev-rev),
53                                        qw(maxdays mindays version),
54                                        qw(data which dist newest),
55                                       ],
56                             default => $default_params,
57                            );
58
59 my ($form_options,$param) = ({},undef);
60 ($form_options,$param)= form_options_and_normal_param(\%param)
61      if $param{form_options};
62
63 %param = %{$param} if defined $param;
64
65 if (exists $param{form_options} and defined $param{form_options}) {
66      delete $param{form_options};
67      delete $param{submit} if exists $param{submit};
68      for my $default (keys %{$default_params}) {
69           if (exists $param{$default} and
70               not ref($default_params->{$default}) and
71               $default_params->{$default} eq $param{$default}
72              ) {
73                delete $param{$default};
74           }
75      }
76      for my $incexc (qw(include exclude)) {
77           next unless exists $param{$incexc};
78           $param{$incexc} = [grep /\S\:\S/, make_list($param{$incexc})];
79      }
80      print $q->redirect(munge_url('pkgreport.cgi?',%param));
81      exit 0;
82 }
83
84 # map from yes|no to 1|0
85 for my $key (qw(repeatmerged bug-rev pend-rev sev-rev)) {
86      if (exists $param{$key}){
87           if ($param{$key} =~ /^no$/i) {
88                $param{$key} = 0;
89           }
90           elsif ($param{$key}) {
91                $param{$key} = 1;
92           }
93      }
94 }
95
96 if (lc($param{archive}) eq 'no') {
97      $param{archive} = 0;
98 }
99 elsif (lc($param{archive}) eq 'yes') {
100      $param{archive} = 1;
101 }
102
103
104 my $include = $param{'&include'} || $param{'include'} || "";
105 my $exclude = $param{'&exclude'} || $param{'exclude'} || "";
106
107 my $users = $param{'users'} || "";
108
109 my $ordering = $param{'ordering'};
110 my $raw_sort = ($param{'raw'} || "no") eq "yes";
111 my $old_view = ($param{'oldview'} || "no") eq "yes";
112 my $age_sort = ($param{'age'} || "no") eq "yes";
113 unless (defined $ordering) {
114    $ordering = "normal";
115    $ordering = "oldview" if $old_view;
116    $ordering = "raw" if $raw_sort;
117    $ordering = 'age' if $age_sort;
118 }
119 $param{ordering} = $ordering;
120
121 our ($bug_order) = $ordering =~ /(age(?:rev)?)/;
122 $bug_order = '' if not defined $bug_order;
123
124 my $bug_rev = ($param{'bug-rev'} || "no") eq "yes";
125 my $pend_rev = ($param{'pend-rev'} || "no") eq "yes";
126 my $sev_rev = ($param{'sev-rev'} || "no") eq "yes";
127
128 my @inc_exc_mapping = ({name   => 'pending',
129                         incexc => 'include',
130                         key    => 'pend-inc',
131                        },
132                        {name   => 'pending',
133                         incexc => 'exclude',
134                         key    => 'pend-exc',
135                        },
136                        {name   => 'severity',
137                         incexc => 'include',
138                         key    => 'sev-inc',
139                        },
140                        {name   => 'severity',
141                         incexc => 'exclude',
142                         key    => 'sev-exc',
143                        },
144                        {name   => 'subject',
145                         incexc => 'include',
146                         key    => 'includesubj',
147                        },
148                        {name   => 'subject',
149                         incexc => 'exclude',
150                         key    => 'excludesubj',
151                        },
152                       );
153 for my $incexcmap (@inc_exc_mapping) {
154      push @{$param{$incexcmap->{incexc}}}, map {"$incexcmap->{name}:$_"}
155           map{split /\s*,\s*/} make_list($param{$incexcmap->{key}})
156                if exists $param{$incexcmap->{key}};
157      delete $param{$incexcmap->{key}};
158 }
159
160
161 my $maxdays = ($param{'maxdays'} || -1);
162 my $mindays = ($param{'mindays'} || 0);
163 my $version = $param{'version'} || undef;
164 # XXX Once the options/selection is rewritten, this should go away
165 my $dist = $param{dist} || undef;
166
167 our %hidden = map { $_, 1 } qw(status severity classification);
168 our %cats = (
169     "status" => [ {
170         "nam" => "Status",
171         "pri" => [map { "pending=$_" }
172             qw(pending forwarded pending-fixed fixed done absent)],
173         "ttl" => ["Outstanding","Forwarded","Pending Upload",
174                   "Fixed in NMU","Resolved","From other Branch"],
175         "def" => "Unknown Pending Status",
176         "ord" => [0,1,2,3,4,5,6],
177     } ],
178     "severity" => [ {
179         "nam" => "Severity",
180         "pri" => [map { "severity=$_" } @gSeverityList],
181         "ttl" => [map { $gSeverityDisplay{$_} } @gSeverityList],
182         "def" => "Unknown Severity",
183         "ord" => [0..@gSeverityList],
184     } ],
185     "classification" => [ {
186         "nam" => "Classification",
187         "pri" => [qw(pending=pending+tag=wontfix 
188                      pending=pending+tag=moreinfo
189                      pending=pending+tag=patch
190                      pending=pending+tag=confirmed
191                      pending=pending)],
192         "ttl" => ["Will Not Fix","More information needed",
193                   "Patch Available","Confirmed"],
194         "def" => "Unclassified",
195         "ord" => [2,3,4,1,0,5],
196     } ],
197     "oldview" => [ qw(status severity) ],
198     "normal" => [ qw(status severity classification) ],
199 );
200
201 if (exists $param{which} and exists $param{data}) {
202      $param{$param{which}} = [exists $param{$param{which}}?(make_list($param{$param{which}})):(),
203                               make_list($param{data}),
204                              ];
205      delete $param{which};
206      delete $param{data};
207 }
208
209 if (defined $param{maintenc}) {
210      $param{maint} = maint_decode($param{maintenc});
211      delete $param{maintenc}
212 }
213
214
215 if (not grep {exists $param{$_}} keys %package_search_keys and exists $param{users}) {
216      $param{usertag} = [make_list($param{users})];
217 }
218
219 if (exists $param{pkg}) {
220      $param{package} = $param{pkg};
221      delete $param{pkg};
222 }
223
224 our %bugusertags;
225 our %ut;
226 for my $user (map {split /[\s*,\s*]+/} make_list($param{users}||[])) {
227     next unless length($user);
228     add_user($user);
229 }
230
231 if (defined $param{usertag}) {
232      for my $usertag (make_list($param{usertag})) {
233           my %select_ut = ();
234           my ($u, $t) = split /:/, $usertag, 2;
235           Debbugs::User::read_usertags(\%select_ut, $u);
236           unless (defined $t && $t ne "") {
237                $t = join(",", keys(%select_ut));
238           }
239           add_user($u);
240           push @{$param{tag}}, split /,/, $t;
241      }
242 }
243
244 quitcgi("You have to choose something to select by") unless grep {exists $param{$_}} keys %package_search_keys;
245
246
247 my $Archived = $param{archive} ? " Archived" : "";
248
249 my $this = munge_url('pkgreport.cgi?',
250                       %param,
251                      );
252
253 my %indexentry;
254 my %strings = ();
255
256 my $dtime = strftime "%a, %e %b %Y %T UTC", gmtime;
257 my $tail_html = $gHTMLTail;
258 $tail_html = $gHTMLTail;
259 $tail_html =~ s/SUBSTITUTE_DTIME/$dtime/;
260
261 our %seen_users;
262 sub add_user {
263     my $ut = \%ut;
264     my $u = shift;
265
266     return if $seen_users{$u};
267     $seen_users{$u} = 1;
268
269     my $user = Debbugs::User::get_user($u);
270
271     my %vis = map { $_, 1 } @{$user->{"visible_cats"}};
272     for my $c (keys %{$user->{"categories"}}) {
273         $cats{$c} = $user->{"categories"}->{$c};
274         $hidden{$c} = 1 unless defined $vis{$c};
275     }
276
277     for my $t (keys %{$user->{"tags"}}) {
278         $ut->{$t} = [] unless defined $ut->{$t};
279         push @{$ut->{$t}}, @{$user->{"tags"}->{$t}};
280     }
281
282     %bugusertags = ();
283     for my $t (keys %{$ut}) {
284         for my $b (@{$ut->{$t}}) {
285             $bugusertags{$b} = [] unless defined $bugusertags{$b};
286             push @{$bugusertags{$b}}, $t;
287         }
288     }
289 #    set_option("bugusertags", \%bugusertags);
290 }
291
292 my @bugs;
293
294 # addusers for source and binary packages being searched for
295 my $pkgsrc = getpkgsrc();
296 my $srcpkg = getsrcpkgs();
297 for my $package (# For binary packages, add the binary package
298                  # and corresponding source package
299                  make_list($param{package}||[]),
300                  (map {defined $pkgsrc->{$_}?($pkgsrc->{$_}):()}
301                   make_list($param{package}||[]),
302                  ),
303                  # For source packages, add the source package
304                  # and corresponding binary packages
305                  make_list($param{src}||[]),
306                  (map {defined $srcpkg->{$_}?($srcpkg->{$_}):()}
307                   make_list($param{src}||[]),
308                  ),
309                 ) {
310      next unless defined $package;
311      add_user($package.'@'.$config{usertag_package_domain})
312           if defined $config{usertag_package_domain};
313 }
314
315
316 # walk through the keys and make the right get_bugs query.
317
318 my $form_option_variables = {};
319 $form_option_variables->{search_key_order} = [@package_search_key_order];
320
321 # Set the title sanely and clean up parameters
322 my @title;
323 my @temp = @package_search_key_order;
324 while (my ($key,$value) = splice @temp, 0, 2) {
325      next unless exists $param{$key};
326      my @entries = ();
327      $param{$key} = [map {split /\s*,\s*/} make_list($param{$key})];
328      for my $entry (make_list($param{$key})) {
329           my $extra = '';
330           if (exists $param{dist} and ($key eq 'package' or $key eq 'src')) {
331                my %versions = get_versions(package => $entry,
332                                            (exists $param{dist}?(dist => $param{dist}):()),
333                                            (exists $param{arch}?(arch => $param{arch}):(arch => $config{default_architectures})),
334                                            ($key eq 'src'?(arch => q(source)):()),
335                                            no_source_arch => 1,
336                                            return_archs => 1,
337                                           );
338                my $verdesc;
339                if (keys %versions > 1) {
340                     $verdesc = 'versions '. join(', ',
341                                     map { $_ .' ['.join(', ',
342                                                     sort @{$versions{$_}}
343                                                    ).']';
344                                    } keys %versions);
345                }
346                else {
347                     $verdesc = 'version '.join(', ',
348                                                keys %versions
349                                               );
350                }
351                $extra= " ($verdesc)" if keys %versions;
352           }
353           push @entries, $entry.$extra;
354      }
355      push @title,$value.' '.join(' or ', @entries);
356 }
357 my $title = $gBugs.' '.join(' and ', map {/ or /?"($_)":$_} @title);
358 @title = ();
359
360 # we have to special case the maint="" search, unfortunatly.
361 if (defined $param{maint} and $param{maint} eq "" or ref($param{maint}) and not @{$param{maint}}) {
362      my %maintainers = %{getmaintainers()};
363      @bugs = get_bugs(function =>
364                       sub {my %d=@_;
365                            foreach my $try (splitpackages($d{"pkg"})) {
366                                 return 1 if not exists $maintainers{$try};
367                            }
368                            return 0;
369                       }
370                      );
371      $title = $gBugs.' in packages with no maintainer';
372 }
373 elsif (defined $param{newest}) {
374      my $newest_bug = newest_bug();
375      @bugs = ($newest_bug - $param{newest} + 1) .. $newest_bug;
376      $title = @bugs.' newest '.$gBugs;
377 }
378 else {
379      #yeah for magick!
380      @bugs = get_bugs((map {exists $param{$_}?($_,$param{$_}):()}
381                        keys %package_search_keys, 'archive'),
382                       usertags => \%ut,
383                      );
384 }
385
386 if (defined $param{version}) {
387      $title .= " at version $param{version}";
388 }
389 elsif (defined $param{dist}) {
390      $title .= " in $param{dist}";
391 }
392
393 $title = html_escape($title);
394
395 my @names; my @prior; my @order;
396 determine_ordering(cats => \%cats,
397                    param => \%param,
398                    ordering => \$ordering,
399                    names => \@names,
400                    prior => \@prior,
401                    title => \@title,
402                    order => \@order,
403                   );
404
405 # strip out duplicate bugs
406 my %bugs;
407 @bugs{@bugs} = @bugs;
408 @bugs = keys %bugs;
409
410 my $result = pkg_htmlizebugs(bugs => \@bugs,
411                              names => \@names,
412                              title => \@title,
413                              order => \@order,
414                              prior => \@prior,
415                              ordering => $ordering,
416                              bugusertags => \%bugusertags,
417                              bug_rev => $bug_rev,
418                              bug_order => $bug_order,
419                              repeatmerged => $param{repeatmerged},
420                              include => $include,
421                              exclude => $exclude,
422                              this => $this,
423                              options => \%param,
424                              (exists $param{dist})?(dist    => $param{dist}):(),
425                             );
426
427 print "Content-Type: text/html; charset=utf-8\n\n";
428
429 print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n";
430 print "<HTML><HEAD>\n" . 
431     "<TITLE>$title -- $gProject$Archived $gBug report logs</TITLE>\n" .
432     qq(<link rel="stylesheet" href="$gWebHostBugDir/css/bugs.css" type="text/css">) .
433     "</HEAD>\n" .
434     '<BODY onload="pagemain();">' .
435     "\n";
436 print "<H1>" . "$gProject$Archived $gBug report logs: $title" .
437       "</H1>\n";
438
439 my $showresult = 1;
440
441 my $pkg = $param{package} if defined $param{package};
442 my $src = $param{src} if defined $param{src};
443
444 my $pseudodesc = getpseudodesc();
445 if (defined $pseudodesc and defined $pkg and exists $pseudodesc->{$pkg}) {
446      delete $param{dist};
447 }
448
449 # output infomration about the packages
450
451 for my $package (make_list($param{package}||[])) {
452      print generate_package_info(binary => 1,
453                                  package => $package,
454                                  options => \%param,
455                                  bugs    => \@bugs,
456                                 );
457 }
458 for my $package (make_list($param{src}||[])) {
459      print generate_package_info(binary => 0,
460                                  package => $package,
461                                  options => \%param,
462                                  bugs    => \@bugs,
463                                 );
464 }
465
466 if (exists $param{maint} or exists $param{maintenc}) {
467     print "<p>Note that maintainers may use different Maintainer fields for\n";
468     print "different packages, so there may be other reports filed under\n";
469     print "different addresses.\n";
470 }
471 if (exists $param{submitter}) {
472     print "<p>Note that people may use different email accounts for\n";
473     print "different bugs, so there may be other reports filed under\n";
474     print "different addresses.\n";
475 }
476
477 # my $archive_links;
478 # my @archive_links;
479 # my %archive_values = (both => 'archived and unarchived',
480 #                     0    => 'not archived',
481 #                     1    => 'archived',
482 #                    );
483 # while (my ($key,$value) = each %archive_values) {
484 #      next if $key eq lc($param{archive});
485 #      push @archive_links, qq(<a href=").
486 #         html_escape(pkg_url((
487 #                      map {
488 #                           $_ eq 'archive'?():($_,$param{$_})
489 #                      } keys %param),
490 #                           archive => $key
491 #                          )).qq(">$value reports </a>);
492 # }
493 # print '<p>See the '.join (' or ',@archive_links)."</p>\n";
494
495 print $result;
496
497 print pkg_javascript() . "\n";
498
499 print qq(<h2 class="outstanding"><!--<a class="options" href="javascript:toggle(1)">-->Options<!--</a>--></h2>\n);
500
501 print option_form(template => 'cgi/pkgreport_options',
502                   param    => \%param,
503                   form_options => $form_options,
504                   variables => $form_option_variables,
505                  );
506
507 # print "<h2 class=\"outstanding\"><a class=\"options\" href=\"javascript:toggle(1)\">Options</a></h2>\n";
508 # print "<div id=\"a_1\">\n";
509 # printf "<form action=\"%s\" method=POST>\n", myurl();
510
511 # print "<table class=\"forms\">\n";
512
513 # my ($checked_any, $checked_sui, $checked_ver) = ("", "", "");
514 # if (defined $dist) {
515 #   $checked_sui = "CHECKED";
516 # } elsif (defined $version) {
517 #   $checked_ver = "CHECKED";
518 # } else {
519 #   $checked_any = "CHECKED";
520 # }
521
522 # print "<tr><td>Show bugs applicable to</td>\n";
523 # print "    <td><input id=\"b_1_1\" name=vt value=none type=radio onchange=\"enable(1);\" $checked_any>anything</td></tr>\n";
524 # print "<tr><td></td>";
525 # print "    <td><input id=\"b_1_2\" name=vt value=bysuite type=radio onchange=\"enable(1);\" $checked_sui>" . pkg_htmlselectsuite(1,2,1) . " for " . pkg_htmlselectarch(1,2,2) . "</td></tr>\n";
526
527 # if (defined $pkg) {
528 #     my $v = html_escape($version) || "";
529 #     my $pkgsane = html_escape($pkg->[0]);
530 #     print "<tr><td></td>";
531 #     print "    <td><input id=\"b_1_3\" name=vt value=bypkg type=radio onchange=\"enable(1);\" $checked_ver>$pkgsane version <input id=\"b_1_3_1\" name=version value=\"$v\"></td></tr>\n";
532 # } elsif (defined $src) {
533 #     my $v = html_escape($version) || "";
534 #     my $srcsane = html_escape($src->[0]);
535 #     print "<tr><td></td>";
536 #     print "    <td><input name=vt value=bysrc type=radio onchange=\"enable(1);\" $checked_ver>$srcsane version <input id=\"b_1_3_1\" name=version value=\"$v\"></td></tr>\n";
537 # }
538 # print "<tr><td>&nbsp;</td></tr>\n";
539
540 # my $includetags = html_escape(join(" ", grep { !m/^subj:/i } map {split /[\s,]+/} ref($include)?@{$include}:$include));
541 # my $excludetags = html_escape(join(" ", grep { !m/^subj:/i } map {split /[\s,]+/} ref($exclude)?@{$exclude}:$exclude));
542 # my $includesubj = html_escape(join(" ", map { s/^subj://i; $_ } grep { m/^subj:/i } map {split /[\s,]+/} ref($include)?@{$include}:$include));
543 # my $excludesubj = html_escape(join(" ", map { s/^subj://i; $_ } grep { m/^subj:/i } map {split /[\s,]+/} ref($exclude)?@{$exclude}:$exclude));
544 # my $vismindays = ($mindays == 0 ? "" : $mindays);
545 # my $vismaxdays = ($maxdays == -1 ? "" : $maxdays);
546
547 # my $sel_rmy = ($param{repeatmerged} ? " selected" : "");
548 # my $sel_rmn = ($param{repeatmerged} ? "" : " selected");
549 # my $sel_ordraw = ($ordering eq "raw" ? " selected" : "");
550 # my $sel_ordold = ($ordering eq "oldview" ? " selected" : "");
551 # my $sel_ordnor = ($ordering eq "normal" ? " selected" : "");
552 # my $sel_ordage = ($ordering eq "age" ? " selected" : "");
553
554 # my $chk_bugrev = ($bug_rev ? " checked" : "");
555 # my $chk_pendrev = ($pend_rev ? " checked" : "");
556 # my $chk_sevrev = ($sev_rev ? " checked" : "");
557
558 # print <<EOF;
559 # <tr><td>Only include bugs tagged with </td><td><input name=include value="$includetags"> or that have <input name=includesubj value="$includesubj"> in their subject</td></tr>
560 # <tr><td>Exclude bugs tagged with </td><td><input name=exclude value="$excludetags"> or that have <input name=excludesubj value="$excludesubj"> in their subject</td></tr>
561 # <tr><td>Only show bugs older than</td><td><input name=mindays value="$vismindays" size=5> days, and younger than <input name=maxdays value="$vismaxdays" size=5> days</td></tr>
562
563 # <tr><td>&nbsp;</td></tr>
564
565 # <tr><td>Merged bugs should be</td><td>
566 # <select name=repeatmerged>
567 # <option value=yes$sel_rmy>displayed separately</option>
568 # <option value=no$sel_rmn>combined</option>
569 # </select>
570 # <tr><td>Categorise bugs by</td><td>
571 # <select name=ordering>
572 # <option value=raw$sel_ordraw>bug number only</option>
573 # <option value=old$sel_ordold>status and severity</option>
574 # <option value=normal$sel_ordnor>status, severity and classification</option>
575 # <option value=age$sel_ordage>status, severity, classification, and age</option>
576 # EOF
577
578 # {
579 # my $any = 0;
580 # my $o = $param{"ordering"} || "";
581 # for my $n (keys %cats) {
582 #     next if ($n eq "normal" || $n eq "oldview");
583 #     next if defined $hidden{$n};
584 #     unless ($any) {
585 #         $any = 1;
586 #       print "<option disabled>------</option>\n";
587 #     }
588 #     my @names = map { ref($_) eq "HASH" ? $_->{"nam"} : $_ } @{$cats{$n}};
589 #     my $name;
590 #     if (@names == 1) { $name = $names[0]; }
591 #     else { $name = " and " . pop(@names); $name = join(", ", @names) . $name; }
592
593 #     printf "<option value=\"%s\"%s>%s</option>\n",
594 #         $n, ($o eq $n ? " selected" : ""), $name;
595 # }
596 # }
597
598 # print "</select></td></tr>\n";
599
600 # printf "<tr><td>Order bugs by</td><td>%s</td></tr>\n",
601 #     pkg_htmlselectyesno("pend-rev", "outstanding bugs first", "done bugs first", $pend_rev);
602 # printf "<tr><td></td><td>%s</td></tr>\n",
603 #     pkg_htmlselectyesno("sev-rev", "highest severity first", "lowest severity first", $sev_rev);
604 # printf "<tr><td></td><td>%s</td></tr>\n",
605 #     pkg_htmlselectyesno("bug-rev", "oldest bugs first", "newest bugs first", $bug_rev);
606
607 # print <<EOF;
608 # <tr><td>&nbsp;</td></tr>
609 # <tr><td colspan=2><input value="Reload page" type="submit"> with new settings</td></tr>
610 # EOF
611
612 # print "</table></form></div>\n";
613
614 print "<hr>\n";
615 print "<p>$tail_html";
616
617 print "</body></html>\n";
618