summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorterry%mozilla.org <>1999-05-27 23:13:40 +0200
committerterry%mozilla.org <>1999-05-27 23:13:40 +0200
commit65aeb54b2937560d2eb4ca46ad9a58c636afb361 (patch)
tree15a4d0f8cd775556fe5852e3807c918f72e92bac
parentb0ce98e67626a85a78ea0defb8533f5adb87e2f3 (diff)
downloadbugzilla-65aeb54b2937560d2eb4ca46ad9a58c636afb361.tar.gz
bugzilla-65aeb54b2937560d2eb4ca46ad9a58c636afb361.tar.xz
Added dependencies, so that you can mark which bugs depend on which
other ones.
-rw-r--r--CHANGES6
-rw-r--r--bug_form.pl82
-rw-r--r--defparams.pl10
-rwxr-xr-xmakedependenciestable.sh43
-rwxr-xr-xprocess_bug.cgi162
-rwxr-xr-xprocessmail30
-rwxr-xr-xshowdependencygraph.cgi165
-rwxr-xr-xshowdependencytree.cgi81
8 files changed, 546 insertions, 33 deletions
diff --git a/CHANGES b/CHANGES
index 0b91ab636..fcba496c0 100644
--- a/CHANGES
+++ b/CHANGES
@@ -10,6 +10,12 @@ query the CVS tree. For example,
will tell you what has been changed in the last week.
+5/27/99 Added support for dependency information. You must run the new
+"makedependenciestable.sh" script. You can turn off dependencies with the new
+"usedependencies" param, but it defaults to being on. Also, read very
+carefully the description for the new "webdotbase" param; you will almost
+certainly need to tweak it.
+
5/24/99 Added "Mac System 8.6" and "Neutrino" to the list of OS's.
Feed this to mysql:
diff --git a/bug_form.pl b/bug_form.pl
index 7757b038c..a2fb1056b 100644
--- a/bug_form.pl
+++ b/bug_form.pl
@@ -106,6 +106,8 @@ sub quoteUrls {
my $loginok = quietly_check_login();
+my $id = $::FORM{'id'};
+
my $query = "
select
bug_id,
@@ -129,7 +131,7 @@ select
groupset,
delta_ts
from bugs
-where bug_id = $::FORM{'id'}
+where bug_id = $id
and bugs.groupset & $::usergroupset = bugs.groupset";
SendSQL($query);
@@ -150,29 +152,29 @@ if (@row = FetchSQLData()) {
$count++;
}
} else {
- SendSQL("select groupset from bugs where bug_id = $::FORM{'id'}");
+ SendSQL("select groupset from bugs where bug_id = $id");
if (@row = FetchSQLData()) {
print "<H1>Permission denied.</H1>\n";
if ($loginok) {
print "Sorry; you do not have the permissions necessary to see\n";
- print "bug $::FORM{'id'}.\n";
+ print "bug $id.\n";
} else {
- print "Sorry; bug $::FORM{'id'} can only be viewed when logged\n";
+ print "Sorry; bug $id can only be viewed when logged\n";
print "into an account with the appropriate permissions. To\n";
print "see this bug, you must first\n";
- print "<a href=\"show_bug.cgi?id=$::FORM{'id'}&GoAheadAndLogIn=1\">";
+ print "<a href=\"show_bug.cgi?id=$id&GoAheadAndLogIn=1\">";
print "log in</a>.";
}
} else {
print "<H1>Bug not found</H1>\n";
- print "There does not seem to be a bug numbered $::FORM{'id'}.\n";
+ print "There does not seem to be a bug numbered $id.\n";
}
exit;
}
$bug{'assigned_to'} = DBID_to_name($bug{'assigned_to'});
$bug{'reporter'} = DBID_to_name($bug{'reporter'});
-$bug{'long_desc'} = GetLongDescription($::FORM{'id'});
+$bug{'long_desc'} = GetLongDescription($id);
my $longdesclength = length($bug{'long_desc'});
@@ -193,7 +195,7 @@ my $component_popup = make_options($::components{$bug{'product'}},
$bug{'component'});
my $cc_element = '<INPUT NAME=cc SIZE=30 VALUE="' .
- ShowCcList($::FORM{'id'}) . '">';
+ ShowCcList($id) . '">';
my $URL = $bug{'bug_file_loc'};
@@ -205,12 +207,12 @@ if (defined $URL && $URL ne "none" && $URL ne "NULL" && $URL ne "") {
}
print "
-<HEAD><TITLE>Bug $::FORM{'id'} -- " . html_quote($bug{'short_desc'}) .
+<HEAD><TITLE>Bug $id -- " . html_quote($bug{'short_desc'}) .
"</TITLE></HEAD><BODY>
<FORM NAME=changeform METHOD=POST ACTION=\"process_bug.cgi\">
<INPUT TYPE=HIDDEN NAME=\"delta_ts\" VALUE=\"$bug{'delta_ts'}\">
<INPUT TYPE=HIDDEN NAME=\"longdesclength\" VALUE=\"$longdesclength\">
-<INPUT TYPE=HIDDEN NAME=\"id\" VALUE=$::FORM{'id'}>
+<INPUT TYPE=HIDDEN NAME=\"id\" VALUE=$id>
<INPUT TYPE=HIDDEN NAME=\"was_assigned_to\" VALUE=\"$bug{'assigned_to'}\">
<TABLE CELLSPACING=0 CELLPADDING=0 BORDER=0><TR>
<TD ALIGN=RIGHT><B>Bug#:</B></TD><TD><A HREF=\"show_bug.cgi?id=$bug{'bug_id'}\">$bug{'bug_id'}</A></TD>
@@ -310,22 +312,64 @@ if (Param("usestatuswhiteboard")) {
}
print "<tr><td align=right><B>Attachments:</b></td>\n";
-SendSQL("select attach_id, creation_ts, description from attachments where bug_id = $::FORM{'id'}");
+SendSQL("select attach_id, creation_ts, description from attachments where bug_id = $id");
while (MoreSQLData()) {
- my ($id, $date, $desc) = (FetchSQLData());
+ my ($attachid, $date, $desc) = (FetchSQLData());
if ($date =~ /^(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/) {
$date = "$3/$4/$2 $5:$6";
}
- my $link = "showattachment.cgi?attach_id=$id";
+ my $link = "showattachment.cgi?attach_id=$attachid";
$desc = value_quote($desc);
print qq{<td><a href="$link">$date</a></td><td colspan=4>$desc</td></tr><tr><td></td>};
- $knownattachments{$id} = 1;
+ $knownattachments{$attachid} = 1;
+}
+print "<td colspan=6><a href=createattachment.cgi?id=$id>Create a new attachment</a> (proposed patch, testcase, etc.)</td></tr></table>\n";
+
+
+sub EmitDependList {
+ my ($desc, $myfield, $targetfield) = (@_);
+ print "<th align=right>$desc:</th><td>";
+ my @list;
+ SendSQL("select dependencies.$targetfield, bugs.bug_status
+ from dependencies, bugs
+ where dependencies.$myfield = $id
+ and bugs.bug_id = dependencies.$targetfield
+ order by dependencies.$targetfield");
+ while (MoreSQLData()) {
+ my ($i, $stat) = (FetchSQLData());
+ push(@list, $i);
+ my $opened = ($stat eq "NEW" || $stat eq "ASSIGNED" ||
+ $stat eq "REOPENED");
+ if (!$opened) {
+ print "<strike>";
+ }
+ print qq{<a href="show_bug.cgi?id=$i">$i</a>};
+ if (!$opened) {
+ print "</strike>";
+ }
+ print " ";
+ }
+ print "</td><td><input name=$targetfield value=\"" .
+ join(',', @list) . "\"></td>\n";
}
-print "<td colspan=6><a href=createattachment.cgi?id=$::FORM{'id'}>Create a new attachment</a> (proposed patch, testcase, etc.)</td></tr>\n";
+if (Param("usedependencies")) {
+ print "<table><tr>\n";
+ EmitDependList("Bugs that bug $id depends on", "blocked", "dependson");
+ print qq{
+<td rowspan=2><a href="showdependencytree.cgi?id=$id">Show dependency tree</a>
+};
+ if (Param("webdotbase") ne "") {
+ print qq{
+<br><a href="showdependencygraph.cgi?id=$id">Show dependency graph</a>
+};
+ }
+ print "</td></tr><tr>";
+ EmitDependList("Bugs depending on bug $id", "dependson", "blocked");
+ print "</tr></table>\n";
+}
print "
-</TABLE>
<br>
<B>Additional Comments:</B>
<BR>
@@ -410,8 +454,8 @@ print "
<INPUT TYPE=hidden name=form_name VALUE=process_bug>
<BR>
<FONT size=\"+1\"><B>
- <A HREF=\"show_activity.cgi?id=$::FORM{'id'}\">View Bug Activity</A>
- <A HREF=\"long_list.cgi?buglist=$::FORM{'id'}\">Format For Printing</A>
+ <A HREF=\"show_activity.cgi?id=$id\">View Bug Activity</A>
+ <A HREF=\"long_list.cgi?buglist=$id\">Format For Printing</A>
</B></FONT><BR>
</FORM>
<table><tr><td align=left><B>Description:</B></td><td width=100%>&nbsp;</td>
@@ -426,7 +470,7 @@ print "
# To add back option of editing the long description, insert after the above
# long_list.cgi line:
-# <A HREF=\"edit_desc.cgi?id=$::FORM{'id'}\">Edit Long Description</A>
+# <A HREF=\"edit_desc.cgi?id=$id\">Edit Long Description</A>
navigation_header();
diff --git a/defparams.pl b/defparams.pl
index ac19dcf09..c471ebd62 100644
--- a/defparams.pl
+++ b/defparams.pl
@@ -292,6 +292,16 @@ DefParam("usebrowserinfo",
"b",
1);
+DefParam("usedependencies",
+ "Do you wish to use dependencies (allowing you to mark which bugs depend on which other ones)?",
+ "b",
+ 1);
+
+DefParam("webdotbase",
+ "This is the URL prefix that is common to all requests for webdot. The <a href=http://www.research.att.com/~north/cgi-bin/webdot.cgi>webdot package</a> is a very swell thing that generates pictures of graphs. If you have an installation of bugsplat that hides behind a firewall, then to get graphs to work, you will have to install a copy of webdot behind your firewall, and change this path to match. Also, webdot has some trouble with software domain names, so you may have to play games and hack the %urlbase% part of this. If this all seems like too much trouble, you can set this paramater to be the empty string, which will cause the graphing feature to be disabled entirely.",
+ "t",
+ "http://www.research.att.com/~north/cgi-bin/webdot.cgi/%urlbase%");
+
DefParam("expectbigqueries",
"If this is on, then we will tell mysql to <tt>set option SQL_BIG_TABLES=1</tt> before doing queries on bugs. This will be a little slower, but one will not get the error <tt>The table ### is full</tt> for big queries that require a big temporary table.",
"b",
diff --git a/makedependenciestable.sh b/makedependenciestable.sh
new file mode 100755
index 000000000..80a6795b2
--- /dev/null
+++ b/makedependenciestable.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+#
+# The contents of this file are subject to the Mozilla Public License
+# Version 1.0 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+# License for the specific language governing rights and limitations
+# under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are Copyright (C) 1998
+# Netscape Communications Corporation. All Rights Reserved.
+#
+# Contributor(s): Terry Weissman <terry@mozilla.org>
+
+mysql > /dev/null 2>/dev/null << OK_ALL_DONE
+
+use bugs;
+
+drop table dependencies
+OK_ALL_DONE
+
+mysql << OK_ALL_DONE
+use bugs;
+create table dependencies (
+ blocked mediumint not null,
+ dependson mediumint not null,
+
+ index(blocked),
+ index(dependson)
+);
+
+
+
+show columns from dependencies;
+show index from dependencies;
+
+OK_ALL_DONE
diff --git a/process_bug.cgi b/process_bug.cgi
index 3c1852d1d..f947869bf 100755
--- a/process_bug.cgi
+++ b/process_bug.cgi
@@ -262,18 +262,46 @@ if ($::comma eq "") {
my $basequery = $::query;
my $delta_ts;
+
sub SnapShotBug {
my ($id) = (@_);
SendSQL("select delta_ts, " . join(',', @::log_columns) .
" from bugs where bug_id = $id");
my @row = FetchSQLData();
$delta_ts = shift @row;
+
return @row;
}
+sub SnapShotDeps {
+ my ($i, $target, $me) = (@_);
+ SendSQL("select $target from dependencies where $me = $i order by $target");
+ my @list;
+ while (MoreSQLData()) {
+ push(@list, FetchOneColumn());
+ }
+ return join(',', @list);
+}
+
+
+my $whoid = DBNameToIdAndCheck($::FORM{'who'});
+my $timestamp;
+
+sub LogDependencyActivity {
+ my ($i, $oldstr, $target, $me) = (@_);
+ my $newstr = SnapShotDeps($i, $target, $me);
+ if ($oldstr ne $newstr) {
+ SendSQL("insert into bugs_activity (bug_id,who,when,field,oldvalue,newvalue) values ($i,$whoid,$timestamp,'$target','$oldstr','$newstr')");
+ return 1;
+ }
+ return 0;
+}
+
+
foreach my $id (@idlist) {
- SendSQL("lock tables bugs write, bugs_activity write, cc write, profiles write");
+ my %dependencychanged;
+ SendSQL("lock tables bugs write, bugs_activity write, cc write, profiles write, dependencies write");
my @oldvalues = SnapShotBug($id);
if (defined $::FORM{'delta_ts'} && $::FORM{'delta_ts'} ne $delta_ts) {
@@ -301,16 +329,66 @@ The changes made were:
print qq{<input type=hidden name="$i" value="$value">\n};
}
print qq{<input type=submit value="Submit my changes anyway">\n};
- print " (This will cause all of the above changes to be overwritten";
+ print " This will cause all of the above changes to be overwritten";
if ($longchanged) {
print ", except for the changes to the description";
}
- print qq{.)</form>\n<li><a href="show_bug.cgi?id=$id">Throw away my changes, and go revisit bug $id</a></ul>\n};
+ print qq{.</form>\n<li><a href="show_bug.cgi?id=$id">Throw away my changes, and go revisit bug $id</a></ul>\n};
navigation_header();
exit;
}
+ my %deps;
+ if (defined $::FORM{'dependson'}) {
+ my $me = "blocked";
+ my $target = "dependson";
+ for (1..2) {
+ $deps{$target} = [];
+ my %seen;
+ foreach my $i (split('[\s,]+', $::FORM{$target})) {
+ if ($i eq "") {
+ next;
+
+ }
+ SendSQL("select bug_id from bugs where bug_id = " .
+ SqlQuote($i));
+ my $comp = FetchOneColumn();
+ if ($comp ne $i) {
+ print "<H1>$i is not a legal bug number</H1>\n";
+ print "<p>Click <b>Back</b> and try again.\n";
+ exit;
+ }
+ if (!exists $seen{$i}) {
+ push(@{$deps{$target}}, $i);
+ $seen{$i} = 1;
+ }
+ }
+ my @stack = @{$deps{$target}};
+ while (@stack) {
+ my $i = shift @stack;
+ SendSQL("select $target from dependencies where $me = $i");
+ while (MoreSQLData()) {
+ my $t = FetchOneColumn();
+ if ($t == $id) {
+ print "<H1>Dependency loop detected!</H1>\n";
+ print "The change you are making to dependencies\n";
+ print "has caused a circular dependency chain.\n";
+ print "<p>Click <b>Back</b> and try again.\n";
+ exit;
+ }
+ if (!exists $seen{$t}) {
+ push @stack, $t;
+ $seen{$t} = 1;
+ }
+ }
+ }
+
+ my $tmp = $me;
+ $me = $target;
+ $target = $tmp;
+ }
+ }
my $query = "$basequery\nwhere bug_id = $id";
@@ -339,9 +417,65 @@ The changes made were:
}
}
+ SendSQL("select delta_ts from bugs where bug_id = $id");
+ $timestamp = FetchOneColumn();
+
+ if (defined $::FORM{'dependson'}) {
+ my $me = "blocked";
+ my $target = "dependson";
+ for (1..2) {
+ SendSQL("select $target from dependencies where $me = $id order by $target");
+ my %snapshot;
+ my @oldlist;
+ while (MoreSQLData()) {
+ push(@oldlist, FetchOneColumn());
+ }
+ my @newlist = sort {$a <=> $b} @{$deps{$target}};
+
+ while (0 < @oldlist || 0 < @newlist) {
+ if (@oldlist == 0 || (@newlist > 0 &&
+ $oldlist[0] > $newlist[0])) {
+ $snapshot{$newlist[0]} = SnapShotDeps($newlist[0], $me,
+ $target);
+ shift @newlist;
+ } elsif (@newlist == 0 || (@oldlist > 0 &&
+ $newlist[0] > $oldlist[0])) {
+ $snapshot{$oldlist[0]} = SnapShotDeps($oldlist[0], $me,
+ $target);
+ shift @oldlist;
+ } else {
+ if ($oldlist[0] != $newlist[0]) {
+ die "Error in list comparing code";
+ }
+ shift @oldlist;
+ shift @newlist;
+ }
+ }
+ my @keys = keys(%snapshot);
+ if (@keys) {
+ my $oldsnap = SnapShotDeps($id, $target, $me);
+ SendSQL("delete from dependencies where $me = $id");
+ foreach my $i (@{$deps{$target}}) {
+ SendSQL("insert into dependencies ($me, $target) values ($id, $i)");
+ }
+ foreach my $k (@keys) {
+ if (LogDependencyActivity($k, $snapshot{$k}, $me,
+ $target)) {
+ $dependencychanged{$k} = 1;
+ }
+
+ }
+ LogDependencyActivity($id, $oldsnap, $target, $me);
+ }
+
+ my $tmp = $me;
+ $me = $target;
+ $target = $tmp;
+ }
+ }
+
+
my @newvalues = SnapShotBug($id);
- my $whoid;
- my $timestamp;
foreach my $col (@::log_columns) {
my $old = shift @oldvalues;
my $new = shift @newvalues;
@@ -352,14 +486,9 @@ The changes made were:
$new = "";
}
if ($old ne $new) {
- if (!defined $whoid) {
- $whoid = DBNameToIdAndCheck($::FORM{'who'});
- SendSQL("select delta_ts from bugs where bug_id = $id");
- $timestamp = FetchOneColumn();
- }
- if ($col eq 'assigned_to') {
- $old = DBID_to_name($old);
- $new = DBID_to_name($new);
+ if ($col eq 'assigned_to' || $col eq 'qa_contact') {
+ $old = DBID_to_name($old) if $old != 0;
+ $new = DBID_to_name($new) if $new != 0;
}
$col = SqlQuote($col);
$old = SqlQuote($old);
@@ -374,6 +503,13 @@ The changes made were:
SendSQL("unlock tables");
system("./processmail $id $::FORM{'who'}");
print "<TD><A HREF=\"show_bug.cgi?id=$id\">Back To BUG# $id</A></TABLE>\n";
+
+ foreach my $k (keys(%dependencychanged)) {
+ print "<TABLE BORDER=1><TD><H2>Dependency changed for bug $k</H2>\n";
+ system("./processmail $k $::FORM{'who'}");
+ print "<TD><A HREF=\"show_bug.cgi?id=$k\">Go To BUG# $k</A></TABLE>\n";
+ }
+
}
if (defined $::next_bug) {
diff --git a/processmail b/processmail
index b5852bbb8..ccc8da271 100755
--- a/processmail
+++ b/processmail
@@ -105,6 +105,34 @@ sub DescCC {
}
+sub DescDependencies {
+ my ($id) = (@_);
+ if (!Param("usedependencies")) {
+ return "";
+ }
+ my $result = "";
+ my $me = "blocked";
+ my $target = "dependson";
+ my $title = "BugsThisDependsOn";
+ for (1..2) {
+ SendSQL("select $target from dependencies where $me = $id order by $target");
+ my @list;
+ while (MoreSQLData()) {
+ push(@list, FetchOneColumn());
+ }
+ if (@list) {
+ $result .= "$title: " . join(',', @list) . "\n";
+ }
+ my $tmp = $me;
+ $me = $target;
+ $target = $tmp;
+ $title = "OtherBugsDependingOnThis";
+ }
+ return $result;
+}
+
+
+
sub GetBugText {
my ($id) = (@_);
undef %::bug;
@@ -171,7 +199,7 @@ AssignedTo: $::bug{'assigned_to'}
ReportedBy: $::bug{'reporter'}
$qa_contact$target_milestone${status_whiteboard}URL: $::bug{'bug_file_loc'}
" . DescCC($::bug{'cclist'}) . "Summary: $::bug{'short_desc'}
-
+" . DescDependencies($id) . "
$::bug{'long_desc'}
";
diff --git a/showdependencygraph.cgi b/showdependencygraph.cgi
new file mode 100755
index 000000000..1e3a02e2a
--- /dev/null
+++ b/showdependencygraph.cgi
@@ -0,0 +1,165 @@
+#!/usr/bonsaitools/bin/perl -w
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public License
+# Version 1.0 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+# License for the specific language governing rights and limitations
+# under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are Copyright (C) 1998
+# Netscape Communications Corporation. All Rights Reserved.
+#
+# Contributor(s): Terry Weissman <terry@mozilla.org>
+
+use diagnostics;
+use strict;
+
+require "CGI.pl";
+
+my $id = $::FORM{'id'};
+my $urlbase = Param("urlbase");
+
+my %seen;
+my %edgesdone;
+
+sub AddLink {
+ my ($blocked, $dependson) = (@_);
+ my $key = "$blocked,$dependson";
+ if (!exists $edgesdone{$key}) {
+ $edgesdone{$key} = 1;
+ print DOT "$blocked -> $dependson\n";
+ $seen{$blocked} = 1;
+ $seen{$dependson} = 1;
+ }
+}
+
+
+print "Content-type: text/html\n\n";
+PutHeader("Dependency graph", "Dependency graph", $id);
+
+if (defined $id) {
+ ConnectToDatabase();
+
+ mkdir("data/webdot", 0777);
+
+ my $filename = "data/webdot/$$.dot";
+ open(DOT, ">$filename") || die "Can't create $filename";
+ print DOT "digraph G {";
+ print DOT qq{
+graph [URL="${urlbase}query.cgi"]
+node [URL="${urlbase}show_bug.cgi?id=\\N", style=filled, color=lightgrey]
+};
+ my %baselist;
+
+ foreach my $i (split('[\s,]+', $::FORM{'id'})) {
+ $i = trim($i);
+ if ($i ne "") {
+ $baselist{$i} = 1;
+ }
+ }
+
+ if ($::FORM{'doall'}) {
+ SendSQL("select blocked, dependson from dependencies");
+
+ while (MoreSQLData()) {
+ my ($blocked, $dependson) = (FetchSQLData());
+ AddLink($blocked, $dependson);
+ }
+ } else {
+ my @stack = keys(%baselist);
+ while (@stack) {
+ my $id = shift @stack;
+ SendSQL("select blocked, dependson from dependencies where blocked = $id or dependson = $id");
+ while (MoreSQLData()) {
+ my ($blocked, $dependson) = (FetchSQLData());
+ if ($blocked != $id && !exists $seen{$blocked}) {
+ push @stack, $blocked;
+ }
+ if ($dependson != $id && !exists $seen{$dependson}) {
+ push @stack, $dependson;
+ }
+ AddLink($blocked, $dependson);
+ }
+ }
+ }
+
+ foreach my $k (keys(%seen)) {
+ my $summary = "";
+ my $stat;
+ if ($::FORM{'showsummary'}) {
+ SendSQL("select bug_status, short_desc from bugs where bug_id = $k");
+ ($stat, $summary) = (FetchSQLData());
+ } else {
+ SendSQL("select bug_status from bugs where bug_id = $k");
+ $stat = FetchOneColumn();
+ }
+ my @params;
+# print DOT "$k [URL" . qq{="${urlbase}show_bug.cgi?id=$k"};
+ if ($summary ne "") {
+ $summary =~ s/([\\\"])/\\$1/g;
+ push(@params, qq{label="$k\\n$summary"});
+ }
+ if (exists $baselist{$k}) {
+ push(@params, "shape=box");
+ }
+ my $opened = ($stat eq "NEW" || $stat eq "ASSIGNED" ||
+ $stat eq "REOPENED");
+ if ($opened) {
+ push(@params, "color=green");
+ }
+ if (@params) {
+ print DOT "$k [" . join(',', @params) . "]\n";
+ } else {
+ print DOT "$k\n";
+ }
+ }
+
+
+ print DOT "}\n";
+ close DOT;
+ chmod 0777, $filename;
+
+ my $url = PerformSubsts(Param("webdotbase")) . $filename;
+
+ print qq{<a href="$url.map"> <img src="$url.gif" ismap> </a><hr>\n};
+
+ # Cleanup any old .dot files created from previous runs.
+ my $since = time() - 24 * 60 * 60;
+ foreach my $f (glob("data/webdot/*.dot")) {
+ if (ModTime($f) < $since) {
+ unlink $f;
+ }
+ }
+} else {
+ $::FORM{'id'} = "";
+ $::FORM{'doall'} = 0;
+ $::FORM{'showsummary'} = 0;
+}
+
+print "
+<form>
+<table>
+<tr>
+<th align=right>Bug numbers:</th>
+<td><input name=id value=\"" . value_quote($::FORM{'id'}) . "\"></td>
+<td><input type=checkbox name=doall" . ($::FORM{'doall'} ? " checked" : "") .
+">Show <b>every</b> bug in the system with
+dependencies</td>
+</tr>
+<tr><td colspan=3><input type=checkbox name=showsummary" .
+($::FORM{'showsummary'} ? " checked" : "") . ">Show the summary of all bugs
+</tr>
+</table>
+<input type=submit value=\"Submit\">
+</form>
+ ";
+
+navigation_header();
diff --git a/showdependencytree.cgi b/showdependencytree.cgi
new file mode 100755
index 000000000..92964648f
--- /dev/null
+++ b/showdependencytree.cgi
@@ -0,0 +1,81 @@
+#!/usr/bonsaitools/bin/perl -w
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public License
+# Version 1.0 (the "License"); you may not use this file except in
+# compliance with the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+# License for the specific language governing rights and limitations
+# under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are Copyright (C) 1998
+# Netscape Communications Corporation. All Rights Reserved.
+#
+# Contributor(s): Terry Weissman <terry@mozilla.org>
+
+use diagnostics;
+use strict;
+
+require "CGI.pl";
+
+# Shut up misguided -w warnings about "used only once":
+
+use vars %::FORM;
+
+
+my $id = $::FORM{'id'};
+my $linkedid = qq{<a href="show_bug.cgi?id=$id">$id</a>};
+
+print "Content-type: text/html\n\n";
+PutHeader("Dependency tree", "Dependency tree", "Bug $linkedid");
+
+ConnectToDatabase();
+
+my %seen;
+
+sub DumpKids {
+ my ($i, $me, $target) = (@_);
+ if (exists $seen{$i}) {
+ return;
+ }
+ $seen{$i} = 1;
+ SendSQL("select $target from dependencies where $me = $i order by $target");
+ my @list;
+ while (MoreSQLData()) {
+ push(@list, FetchOneColumn());
+ }
+ if (@list) {
+ print "<ul>\n";
+ foreach my $kid (@list) {
+ SendSQL("select bug_status, short_desc from bugs where bug_id = $kid");
+ my ($stat, $short_desc) = (FetchSQLData());
+ my $opened = ($stat eq "NEW" || $stat eq "ASSIGNED" ||
+ $stat eq "REOPENED");
+ print "<li>";
+ if (!$opened) {
+ print "<strike>";
+ }
+ $short_desc = html_quote($short_desc);
+ print qq{<a href="show_bug.cgi?id=$kid">$kid $short_desc</a>};
+ if (!$opened) {
+ print "</strike>";
+ }
+ DumpKids($kid, $me, $target);
+ }
+ print "</ul>\n";
+ }
+}
+
+print "<h1>Bugs that bug $linkedid depends on</h1>";
+DumpKids($id, "blocked", "dependson");
+print "<h1>Bugs that depend on bug $linkedid</h1>";
+undef %seen;
+DumpKids($id, "dependson", "blocked");
+
+navigation_header();