2003-03-27 00:07:02 +00:00
|
|
|
#!/usr/bin/perl -wT
|
1999-05-27 14:13:41 +00:00
|
|
|
# -*- Mode: perl; indent-tabs-mode: nil -*-
|
|
|
|
#
|
1999-11-01 23:33:56 +00:00
|
|
|
# The contents of this file are subject to the Mozilla Public
|
|
|
|
# License Version 1.1 (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.
|
|
|
|
#
|
1999-05-27 14:13:41 +00:00
|
|
|
# The Original Code is the Bugzilla Bug Tracking System.
|
1999-11-01 23:33:56 +00:00
|
|
|
#
|
1999-05-27 14:13:41 +00:00
|
|
|
# The Initial Developer of the Original Code is Netscape Communications
|
1999-11-01 23:33:56 +00:00
|
|
|
# Corporation. Portions created by Netscape are
|
|
|
|
# Copyright (C) 1998 Netscape Communications Corporation. All
|
|
|
|
# Rights Reserved.
|
|
|
|
#
|
1999-05-27 14:13:41 +00:00
|
|
|
# Contributor(s): Terry Weissman <terry@mozilla.org>
|
2002-04-04 07:39:19 +00:00
|
|
|
# Gervase Markham <gerv@gerv.net>
|
1999-05-27 14:13:41 +00:00
|
|
|
|
|
|
|
use strict;
|
|
|
|
|
2002-01-20 01:44:52 +00:00
|
|
|
use lib qw(.);
|
|
|
|
|
2003-04-24 21:17:31 +00:00
|
|
|
use File::Temp;
|
2006-06-21 00:44:48 +00:00
|
|
|
|
2003-05-05 01:15:38 +00:00
|
|
|
use Bugzilla;
|
2006-06-21 00:44:48 +00:00
|
|
|
use Bugzilla::Constants;
|
2005-01-27 20:08:34 +00:00
|
|
|
use Bugzilla::Util;
|
2006-06-21 00:44:48 +00:00
|
|
|
use Bugzilla::Error;
|
2005-07-20 11:29:33 +00:00
|
|
|
use Bugzilla::Bug;
|
2003-04-24 21:17:31 +00:00
|
|
|
|
2004-03-27 03:51:44 +00:00
|
|
|
Bugzilla->login();
|
2001-05-31 15:52:25 +00:00
|
|
|
|
2003-05-05 01:15:38 +00:00
|
|
|
my $cgi = Bugzilla->cgi;
|
2005-10-24 23:11:56 +00:00
|
|
|
my $template = Bugzilla->template;
|
|
|
|
my $vars = {};
|
2003-01-24 10:59:08 +00:00
|
|
|
# Connect to the shadow database if this installation is using one to improve
|
|
|
|
# performance.
|
2005-11-13 17:50:47 +00:00
|
|
|
my $dbh = Bugzilla->switch_to_shadow_db();
|
2003-01-24 10:59:08 +00:00
|
|
|
|
2006-07-06 06:12:05 +00:00
|
|
|
local our (%seen, %edgesdone, %bugtitles);
|
2003-12-03 18:31:52 +00:00
|
|
|
|
|
|
|
# CreateImagemap: This sub grabs a local filename as a parameter, reads the
|
|
|
|
# dot-generated image map datafile residing in that file and turns it into
|
|
|
|
# an HTML map element. THIS SUB IS ONLY USED FOR LOCAL DOT INSTALLATIONS.
|
|
|
|
# The map datafile won't necessarily contain the bug summaries, so we'll
|
|
|
|
# pull possible HTML titles from the %bugtitles hash (filled elsewhere
|
|
|
|
# in the code)
|
|
|
|
|
|
|
|
# The dot mapdata lines have the following format (\nsummary is optional):
|
|
|
|
# rectangle (LEFTX,TOPY) (RIGHTX,BOTTOMY) URLBASE/show_bug.cgi?id=BUGNUM BUGNUM[\nSUMMARY]
|
1999-05-27 14:13:41 +00:00
|
|
|
|
2002-05-07 09:14:38 +00:00
|
|
|
sub CreateImagemap {
|
|
|
|
my $mapfilename = shift;
|
|
|
|
my $map = "<map name=\"imagemap\">\n";
|
|
|
|
my $default;
|
|
|
|
|
|
|
|
open MAP, "<$mapfilename";
|
|
|
|
while(my $line = <MAP>) {
|
|
|
|
if($line =~ /^default ([^ ]*)(.*)$/) {
|
2002-06-28 00:18:32 +00:00
|
|
|
$default = qq{<area alt="" shape="default" href="$1">\n};
|
2002-05-07 09:14:38 +00:00
|
|
|
}
|
2003-12-03 18:31:52 +00:00
|
|
|
|
2002-05-07 09:14:38 +00:00
|
|
|
if ($line =~ /^rectangle \((.*),(.*)\) \((.*),(.*)\) (http[^ ]*)(.*)?$/) {
|
2003-12-03 18:31:52 +00:00
|
|
|
my ($leftx, $rightx, $topy, $bottomy, $url) = ($1, $3, $2, $4, $5);
|
|
|
|
|
|
|
|
# Pick up bugid from the mapdata label field. Getting the title from
|
|
|
|
# bugtitle hash instead of mapdata allows us to get the summary even
|
|
|
|
# when showsummary is off, and also gives us status and resolution.
|
|
|
|
|
|
|
|
my ($bugid) = ($6 =~ /^\s*(\d+)/);
|
|
|
|
my $bugtitle = value_quote($bugtitles{$bugid});
|
|
|
|
$map .= qq{<area alt="bug $bugid" name="bug$bugid" shape="rect" } .
|
|
|
|
qq{title="$bugtitle" href="$url" } .
|
|
|
|
qq{coords="$leftx,$topy,$rightx,$bottomy">\n};
|
2002-05-07 09:14:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
close MAP;
|
|
|
|
|
|
|
|
$map .= "$default</map>";
|
|
|
|
return $map;
|
|
|
|
}
|
|
|
|
|
1999-05-27 14:13:41 +00:00
|
|
|
sub AddLink {
|
2003-04-24 21:17:31 +00:00
|
|
|
my ($blocked, $dependson, $fh) = (@_);
|
1999-05-27 14:13:41 +00:00
|
|
|
my $key = "$blocked,$dependson";
|
|
|
|
if (!exists $edgesdone{$key}) {
|
|
|
|
$edgesdone{$key} = 1;
|
2003-04-24 21:17:31 +00:00
|
|
|
print $fh "$blocked -> $dependson\n";
|
1999-05-27 14:13:41 +00:00
|
|
|
$seen{$blocked} = 1;
|
|
|
|
$seen{$dependson} = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-03-26 21:00:11 +00:00
|
|
|
my $rankdir = $cgi->param('rankdir') || "LR";
|
2006-06-21 00:44:48 +00:00
|
|
|
my $webdotdir = bz_locations()->{'webdotdir'};
|
1999-05-27 20:20:57 +00:00
|
|
|
|
2004-03-26 21:00:11 +00:00
|
|
|
if (!defined $cgi->param('id') && !defined $cgi->param('doall')) {
|
2002-10-06 11:52:37 +00:00
|
|
|
ThrowCodeError("missing_bug_id");
|
2004-03-26 21:00:11 +00:00
|
|
|
}
|
2002-04-04 07:39:19 +00:00
|
|
|
|
2003-04-24 21:17:31 +00:00
|
|
|
my ($fh, $filename) = File::Temp::tempfile("XXXXXXXXXX",
|
|
|
|
SUFFIX => '.dot',
|
2003-11-22 03:50:42 +00:00
|
|
|
DIR => $webdotdir);
|
2006-07-03 21:26:22 +00:00
|
|
|
my $urlbase = Bugzilla->params->{'urlbase'};
|
1999-05-27 14:13:41 +00:00
|
|
|
|
2003-04-24 21:17:31 +00:00
|
|
|
print $fh "digraph G {";
|
|
|
|
print $fh qq{
|
2005-08-09 19:41:35 +00:00
|
|
|
graph [URL="${urlbase}query.cgi", rankdir=$rankdir]
|
1999-05-27 14:13:41 +00:00
|
|
|
node [URL="${urlbase}show_bug.cgi?id=\\N", style=filled, color=lightgrey]
|
|
|
|
};
|
|
|
|
|
2002-04-04 07:39:19 +00:00
|
|
|
my %baselist;
|
1999-05-27 14:13:41 +00:00
|
|
|
|
2004-03-26 21:00:11 +00:00
|
|
|
if ($cgi->param('doall')) {
|
2005-10-26 16:15:50 +00:00
|
|
|
my $dependencies = $dbh->selectall_arrayref(
|
|
|
|
"SELECT blocked, dependson FROM dependencies");
|
2002-04-04 07:39:19 +00:00
|
|
|
|
2005-10-26 16:15:50 +00:00
|
|
|
foreach my $dependency (@$dependencies) {
|
|
|
|
my ($blocked, $dependson) = @$dependency;
|
2003-04-24 21:17:31 +00:00
|
|
|
AddLink($blocked, $dependson, $fh);
|
2002-04-04 07:39:19 +00:00
|
|
|
}
|
|
|
|
} else {
|
2004-03-26 21:00:11 +00:00
|
|
|
foreach my $i (split('[\s,]+', $cgi->param('id'))) {
|
2002-05-02 07:03:00 +00:00
|
|
|
$i = trim($i);
|
|
|
|
ValidateBugID($i);
|
|
|
|
$baselist{$i} = 1;
|
|
|
|
}
|
|
|
|
|
2002-04-04 07:39:19 +00:00
|
|
|
my @stack = keys(%baselist);
|
2005-10-26 16:15:50 +00:00
|
|
|
my $sth = $dbh->prepare(
|
|
|
|
q{SELECT blocked, dependson
|
|
|
|
FROM dependencies
|
|
|
|
WHERE blocked = ? or dependson = ?});
|
2002-04-04 07:39:19 +00:00
|
|
|
foreach my $id (@stack) {
|
2005-10-26 16:15:50 +00:00
|
|
|
my $dependencies = $dbh->selectall_arrayref($sth, undef, ($id, $id));
|
|
|
|
foreach my $dependency (@$dependencies) {
|
|
|
|
my ($blocked, $dependson) = @$dependency;
|
2002-04-04 07:39:19 +00:00
|
|
|
if ($blocked != $id && !exists $seen{$blocked}) {
|
|
|
|
push @stack, $blocked;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($dependson != $id && !exists $seen{$dependson}) {
|
|
|
|
push @stack, $dependson;
|
|
|
|
}
|
|
|
|
|
2003-04-24 21:17:31 +00:00
|
|
|
AddLink($blocked, $dependson, $fh);
|
1999-05-27 14:13:41 +00:00
|
|
|
}
|
2002-04-04 07:39:19 +00:00
|
|
|
}
|
|
|
|
|
2002-05-02 07:03:00 +00:00
|
|
|
foreach my $k (keys(%baselist)) {
|
|
|
|
$seen{$k} = 1;
|
|
|
|
}
|
2002-04-04 07:39:19 +00:00
|
|
|
}
|
|
|
|
|
2005-10-26 16:15:50 +00:00
|
|
|
my $sth = $dbh->prepare(
|
|
|
|
q{SELECT bug_status, resolution, short_desc
|
|
|
|
FROM bugs
|
|
|
|
WHERE bugs.bug_id = ?});
|
2002-04-04 07:39:19 +00:00
|
|
|
foreach my $k (keys(%seen)) {
|
2003-12-03 18:31:52 +00:00
|
|
|
# Retrieve bug information from the database
|
2005-10-26 16:15:50 +00:00
|
|
|
my ($stat, $resolution, $summary) = $dbh->selectrow_array($sth, undef, $k);
|
2003-12-03 18:31:52 +00:00
|
|
|
$stat ||= 'NEW';
|
|
|
|
$resolution ||= '';
|
|
|
|
$summary ||= '';
|
|
|
|
|
|
|
|
# Resolution and summary are shown only if user can see the bug
|
2004-08-04 16:17:10 +00:00
|
|
|
if (!Bugzilla->user->can_see_bug($k)) {
|
2003-12-03 18:31:52 +00:00
|
|
|
$resolution = $summary = '';
|
1999-05-27 14:13:41 +00:00
|
|
|
}
|
2003-12-03 18:31:52 +00:00
|
|
|
|
2005-10-12 01:04:30 +00:00
|
|
|
$vars->{'short_desc'} = $summary if ($k eq $cgi->param('id'));
|
2003-12-03 18:31:52 +00:00
|
|
|
|
2002-04-04 07:39:19 +00:00
|
|
|
my @params;
|
1999-05-27 14:13:41 +00:00
|
|
|
|
2004-03-26 21:00:11 +00:00
|
|
|
if ($summary ne "" && $cgi->param('showsummary')) {
|
2002-04-04 07:39:19 +00:00
|
|
|
$summary =~ s/([\\\"])/\\$1/g;
|
|
|
|
push(@params, qq{label="$k\\n$summary"});
|
1999-05-27 14:42:19 +00:00
|
|
|
}
|
2002-04-04 07:39:19 +00:00
|
|
|
|
|
|
|
if (exists $baselist{$k}) {
|
|
|
|
push(@params, "shape=box");
|
1999-05-27 14:13:41 +00:00
|
|
|
}
|
|
|
|
|
2006-03-06 21:42:10 +00:00
|
|
|
if (is_open_state($stat)) {
|
2002-04-04 07:39:19 +00:00
|
|
|
push(@params, "color=green");
|
|
|
|
}
|
1999-05-27 14:13:41 +00:00
|
|
|
|
2002-04-04 07:39:19 +00:00
|
|
|
if (@params) {
|
2003-04-24 21:17:31 +00:00
|
|
|
print $fh "$k [" . join(',', @params) . "]\n";
|
2002-03-31 04:19:07 +00:00
|
|
|
} else {
|
2003-04-24 21:17:31 +00:00
|
|
|
print $fh "$k\n";
|
1999-05-27 14:13:41 +00:00
|
|
|
}
|
2003-12-03 18:31:52 +00:00
|
|
|
|
|
|
|
# Push the bug tooltip texts into a global hash so that
|
|
|
|
# CreateImagemap sub (used with local dot installations) can
|
|
|
|
# use them later on.
|
|
|
|
$bugtitles{$k} = trim("$stat $resolution");
|
|
|
|
|
|
|
|
# Show the bug summary in tooltips only if not shown on
|
|
|
|
# the graph and it is non-empty (the user can see the bug)
|
2004-03-26 21:00:11 +00:00
|
|
|
if (!$cgi->param('showsummary') && $summary ne "") {
|
2003-12-03 18:31:52 +00:00
|
|
|
$bugtitles{$k} .= " - $summary";
|
|
|
|
}
|
2002-04-04 07:39:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-04-24 21:17:31 +00:00
|
|
|
print $fh "}\n";
|
|
|
|
close $fh;
|
2002-04-04 07:39:19 +00:00
|
|
|
|
|
|
|
chmod 0777, $filename;
|
|
|
|
|
2006-07-03 21:26:22 +00:00
|
|
|
my $webdotbase = Bugzilla->params->{'webdotbase'};
|
2002-04-04 07:39:19 +00:00
|
|
|
|
|
|
|
if ($webdotbase =~ /^https?:/) {
|
|
|
|
# Remote dot server
|
2005-08-15 17:58:19 +00:00
|
|
|
my $url = perform_substs($webdotbase) . $filename;
|
2002-04-04 07:39:19 +00:00
|
|
|
$vars->{'image_url'} = $url . ".gif";
|
|
|
|
$vars->{'map_url'} = $url . ".map";
|
1999-05-27 14:13:41 +00:00
|
|
|
} else {
|
2002-04-04 07:39:19 +00:00
|
|
|
# Local dot installation
|
2003-12-03 18:31:52 +00:00
|
|
|
|
|
|
|
# First, generate the png image file from the .dot source
|
|
|
|
|
2003-04-24 21:17:31 +00:00
|
|
|
my ($pngfh, $pngfilename) = File::Temp::tempfile("XXXXXXXXXX",
|
|
|
|
SUFFIX => '.png',
|
2003-11-22 03:50:42 +00:00
|
|
|
DIR => $webdotdir);
|
2004-06-22 08:05:49 +00:00
|
|
|
binmode $pngfh;
|
2006-02-07 09:22:25 +00:00
|
|
|
open(DOT, "\"$webdotbase\" -Tpng $filename|");
|
2004-06-22 08:05:49 +00:00
|
|
|
binmode DOT;
|
2003-04-24 21:17:31 +00:00
|
|
|
print $pngfh $_ while <DOT>;
|
|
|
|
close DOT;
|
|
|
|
close $pngfh;
|
2004-06-22 08:05:49 +00:00
|
|
|
|
|
|
|
# On Windows $pngfilename will contain \ instead of /
|
|
|
|
$pngfilename =~ s|\\|/|g if $^O eq 'MSWin32';
|
|
|
|
|
2002-04-04 07:39:19 +00:00
|
|
|
$vars->{'image_url'} = $pngfilename;
|
2003-04-24 21:17:31 +00:00
|
|
|
|
2003-12-03 18:31:52 +00:00
|
|
|
# Then, generate a imagemap datafile that contains the corner data
|
|
|
|
# for drawn bug objects. Pass it on to CreateImagemap that
|
|
|
|
# turns this monster into html.
|
|
|
|
|
2003-04-24 21:17:31 +00:00
|
|
|
my ($mapfh, $mapfilename) = File::Temp::tempfile("XXXXXXXXXX",
|
|
|
|
SUFFIX => '.map',
|
2003-11-22 03:50:42 +00:00
|
|
|
DIR => $webdotdir);
|
2004-06-22 08:05:49 +00:00
|
|
|
binmode $mapfh;
|
2006-02-07 09:22:25 +00:00
|
|
|
open(DOT, "\"$webdotbase\" -Tismap $filename|");
|
2004-06-22 08:05:49 +00:00
|
|
|
binmode DOT;
|
2003-04-24 21:17:31 +00:00
|
|
|
print $mapfh $_ while <DOT>;
|
|
|
|
close DOT;
|
|
|
|
close $mapfh;
|
2002-05-07 09:14:38 +00:00
|
|
|
$vars->{'image_map'} = CreateImagemap($mapfilename);
|
2002-04-04 07:39:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# Cleanup any old .dot files created from previous runs.
|
|
|
|
my $since = time() - 24 * 60 * 60;
|
2002-07-09 23:40:32 +00:00
|
|
|
# Can't use glob, since even calling that fails taint checks for perl < 5.6
|
2003-11-22 03:50:42 +00:00
|
|
|
opendir(DIR, $webdotdir);
|
|
|
|
my @files = grep { /\.dot$|\.png$|\.map$/ && -f "$webdotdir/$_" } readdir(DIR);
|
2002-07-09 23:40:32 +00:00
|
|
|
closedir DIR;
|
|
|
|
foreach my $f (@files)
|
2002-04-04 07:39:19 +00:00
|
|
|
{
|
2003-11-22 03:50:42 +00:00
|
|
|
$f = "$webdotdir/$f";
|
2002-04-04 07:39:19 +00:00
|
|
|
# Here we are deleting all old files. All entries are from the
|
2003-11-22 03:50:42 +00:00
|
|
|
# $webdot directory. Since we're deleting the file (not following
|
2002-04-04 07:39:19 +00:00
|
|
|
# symlinks), this can't escape to delete anything it shouldn't
|
2003-11-22 03:50:42 +00:00
|
|
|
# (unless someone moves the location of $webdotdir, of course)
|
2002-04-04 07:39:19 +00:00
|
|
|
trick_taint($f);
|
2005-01-27 20:08:34 +00:00
|
|
|
if (file_mod_time($f) < $since) {
|
2002-04-04 07:39:19 +00:00
|
|
|
unlink $f;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-03-26 21:00:11 +00:00
|
|
|
$vars->{'bug_id'} = $cgi->param('id');
|
|
|
|
$vars->{'multiple_bugs'} = ($cgi->param('id') =~ /[ ,]/);
|
|
|
|
$vars->{'doall'} = $cgi->param('doall');
|
|
|
|
$vars->{'rankdir'} = $rankdir;
|
|
|
|
$vars->{'showsummary'} = $cgi->param('showsummary');
|
1999-05-27 14:13:41 +00:00
|
|
|
|
2002-04-04 07:39:19 +00:00
|
|
|
# Generate and return the UI (HTML page) from the appropriate template.
|
2003-05-05 01:15:38 +00:00
|
|
|
print $cgi->header();
|
2002-04-24 07:24:50 +00:00
|
|
|
$template->process("bug/dependency-graph.html.tmpl", $vars)
|
|
|
|
|| ThrowTemplateError($template->error());
|