showdependencytree.cgi 6.76 KB
Newer Older
1
#!/usr/bonsaitools/bin/perl -wT
2 3
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
4 5 6 7 8 9 10 11 12 13
# 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.
#
14
# The Original Code is the Bugzilla Bug Tracking System.
15
#
16
# The Initial Developer of the Original Code is Netscape Communications
17 18 19 20
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
21
# Contributor(s): Terry Weissman <terry@mozilla.org>
22 23
#                 Andreas Franke <afranke@mathweb.org>
#                 Christian Reis <kiko@async.com.br>
24
#                 Myk Melez <myk@mozilla.org>
25 26 27 28

use diagnostics;
use strict;

29
use lib qw(.);
30 31
require "CGI.pl";

32 33 34
# Use global template variables.
use vars qw($template $vars);

35 36
use vars %::FORM;

37 38 39 40
ConnectToDatabase();

quietly_check_login();

41 42 43
# More warning suppression silliness.
$::userid = $::userid;
$::usergroupset = $::usergroupset;
44

45 46 47
################################################################################
# Data/Security Validation                                                     #
################################################################################
48 49

# Make sure the bug ID is a positive integer representing an existing
50
# bug that the user is authorized to access.
51
ValidateBugID($::FORM{'id'});
52 53
my $id = $::FORM{'id'};

54
my $hide_resolved = $::FORM{'hide_resolved'} ? 1 : 0;
55

56 57
my $maxdepth = $::FORM{'maxdepth'} || 0;
if ($maxdepth !~ /^\d+$/) { $maxdepth = 0 };
58

59 60 61
################################################################################
# Main Section                                                                 #
################################################################################
62

63 64 65 66 67 68
# The column/value to select as the target milestone for bugs,
# either the target_milestone column or the empty string value
# (for installations that don't use target milestones).  Makes
# it easier to query the database for bugs because we don't
# have to embed a conditional statement into each query.
my $milestone_column = Param('usetargetmilestone') ? "target_milestone" : "''";
69

70
# The greatest depth to which either tree goes.
71 72
my $realdepth = 0;

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
# Generate the tree of bugs that this bug depends on and a list of IDs
# appearing in the tree.
my $dependson_tree = { $id => GetBug($id) };
my $dependson_ids = {};
GenerateTree($id, "dependson", 1, $dependson_tree, $dependson_ids);
$vars->{'dependson_tree'} = $dependson_tree;
$vars->{'dependson_ids'} = [keys(%$dependson_ids)];

# Generate the tree of bugs that this bug blocks and a list of IDs
# appearing in the tree.
my $blocked_tree = { $id => GetBug($id) };
my $blocked_ids = {};
GenerateTree($id, "blocked", 1, $blocked_tree, $blocked_ids);
$vars->{'blocked_tree'} = $blocked_tree;
$vars->{'blocked_ids'} = [keys(%$blocked_ids)];

$vars->{'realdepth'}      = $realdepth;

$vars->{'bugid'}          = $id;
$vars->{'maxdepth'}       = $maxdepth;
$vars->{'hide_resolved'}  = $hide_resolved;
$vars->{'canedit'}        = UserInGroup("editbugs");

print "Content-Type: text/html\n\n";
97 98
$template->process("bug/dependency-tree.html.tmpl", $vars)
  || ThrowTemplateError($template->error());
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127

################################################################################
# Recursive Tree Generation Function                                           #
################################################################################

sub GenerateTree {
    # Generates a dependency tree for a given bug.  Calls itself recursively
    # to generate sub-trees for the bug's dependencies.
    
    my ($bug_id, $relationship, $depth, $bugs, $ids) = @_;
    
    # Query the database for bugs with the given dependency relationship.
    my @dependencies = GetDependencies($bug_id, $relationship);
    
    # Don't do anything if this bug doesn't have any dependencies.
    return unless scalar(@dependencies);
    
    # Record this depth in the global $realdepth variable if it's farther 
    # than we've gone before.
    $realdepth = max($realdepth, $depth);

    foreach my $dep_id (@dependencies) {
        # Get this dependency's record from the database and generate
        # its sub-tree if we haven't already done so (which happens
        # when bugs appear in dependency trees multiple times).
        if (!$bugs->{$dep_id}) {
            $bugs->{$dep_id} = GetBug($dep_id);
            GenerateTree($dep_id, $relationship, $depth+1, $bugs, $ids);
        }
128

129 130 131 132 133 134 135 136 137 138
        # Add this dependency to the list of this bug's dependencies 
        # if it exists, if we haven't exceeded the maximum depth the user 
        # wants the tree to go, and if the dependency isn't resolved 
        # (if we're ignoring resolved dependencies).
        if ($bugs->{$dep_id}->{'exists'}
            && (!$maxdepth || $depth <= $maxdepth) 
            && ($bugs->{$dep_id}->{'open'} || !$hide_resolved))
        {
            push (@{$bugs->{$bug_id}->{'dependencies'}}, $dep_id);
            $ids->{$dep_id} = 1;
139 140 141 142
        }
    }
}

143 144 145 146
sub GetBug {
    # Retrieves the necessary information about a bug, stores it in the bug cache,
    # and returns it to the calling code.
    my ($id) = @_;
147
    
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
    SendSQL(SelectVisible("SELECT 1, 
                                  bug_status, 
                                  short_desc, 
                                  $milestone_column, 
                                  assignee.userid, 
                                  assignee.login_name
                             FROM bugs, profiles AS assignee
                            WHERE bugs.bug_id = $id
                              AND bugs.assigned_to = assignee.userid", 
                          $::userid, 
                          $::usergroupset));
    
    my $bug = {};
    
    ($bug->{'exists'}, 
     $bug->{'status'}, 
     $bug->{'summary'}, 
     $bug->{'milestone'}, 
     $bug->{'assignee_id'}, 
     $bug->{'assignee_email'}) = FetchSQLData();
    
    $bug->{'open'} = IsOpenedState($bug->{'status'});
170
    $bug->{'dependencies'} = [];
171 172
    
    return $bug;
173 174
}

175 176
sub GetDependencies {
    # Returns a list of dependencies for a given bug.
177
    
178
    my ($id, $relationship) = @_;
179
    
180
    my $bug_type = ($relationship eq "blocked") ? "dependson" : "blocked";
181
    
182 183 184 185
    SendSQL("  SELECT $relationship 
                 FROM dependencies 
                WHERE $bug_type = $id 
             ORDER BY $relationship");
186
    
187 188 189 190
    my @dependencies = ();
    push(@dependencies, FetchOneColumn()) while MoreSQLData();
    
    return @dependencies;
191 192
}