~mkanat/bugzilla-traceparser/trunk

« back to all changes in this revision

Viewing changes to Extension.pm

  • Committer: Max Kanat-Alexander
  • Date: 2010-02-08 03:40:24 UTC
  • Revision ID: mkanat@bugzilla.org-20100208034024-2jr17lgakmfuls85
Convert extension code to using the 3.6 extension format.
Currently compiles and passes checksetup.pl, but hasn't been fully tested.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- Mode: perl; indent-tabs-mode: nil -*-
2
 
#
3
1
# The contents of this file are subject to the Mozilla Public
4
2
# License Version 1.1 (the "License"); you may not use this file
5
3
# except in compliance with the License. You may obtain a copy of
10
8
# implied. See the License for the specific language governing
11
9
# rights and limitations under the License.
12
10
#
13
 
# The Original Code is the Bugzilla Bug Tracking System.
 
11
# The Original Code is the Bugzilla TraceParser Plugin.
14
12
#
15
13
# The Initial Developer of the Original Code is Canonical Ltd.
16
 
# Portions created by the Initial Developer are Copyright (C) 2009
17
 
# the Initial Developer. All Rights Reserved.
 
14
# Portions created by Canonical Ltd. are Copyright (C) 2009
 
15
# Canonical Ltd. All Rights Reserved.
18
16
#
19
 
# Contributor(s): 
 
17
# Contributor(s):
20
18
#   Max Kanat-Alexander <mkanat@bugzilla.org>
21
19
 
22
 
package TraceParser::Hooks;
 
20
package Bugzilla::Extension::TraceParser;
23
21
use strict;
24
 
use base qw(Exporter);
 
22
use base qw(Bugzilla::Extension);
 
23
 
25
24
use Bugzilla::Bug;
26
25
use Bugzilla::Constants;
27
26
use Bugzilla::Error;
 
27
use Bugzilla::Group;
28
28
use Bugzilla::Install::Util qw(indicate_progress);
 
29
use Bugzilla::User::Setting qw(add_setting);
29
30
use Bugzilla::Util qw(detaint_natural);
30
31
 
31
 
use TraceParser::Trace;
 
32
use Bugzilla::Extension::TraceParser::Trace;
32
33
 
33
34
use List::Util;
34
35
use POSIX qw(ceil);
35
36
 
36
 
our @EXPORT = qw(
37
 
    bug_create
38
 
    bug_update
39
 
    install_update_db
40
 
    format_comment
41
 
    page
42
 
);
 
37
our $VERSION = '0.01';
43
38
 
44
39
use constant DEFAULT_POPULAR_LIMIT => 20;
45
40
 
46
 
sub bug_create {
47
 
    my %params = @_;
48
 
    my $bug = $params{bug};
 
41
sub bug_end_of_create {
 
42
    my ($self, $args) = @_;
 
43
    
 
44
    my $bug = $args->{bug};
49
45
    my $comments = Bugzilla::Bug::GetComments($bug->id, 'oldest_to_newest',
50
46
        '1970-01-01', $bug->creation_ts, 'raw');
51
47
    my $comment = $comments->[0];
52
 
    my $data = TraceParser::Trace->parse_from_text($comment->{body});
 
48
    my $data = Bugzilla::Extension::TraceParser::Trace->parse_from_text($comment->{body});
53
49
    return if !$data;
54
 
    my $trace = TraceParser::Trace->create(
 
50
    my $trace = Bugzilla::Extension::TraceParser::Trace->create(
55
51
        { %$data, comment_id => $comment->{id} });
56
 
    _check_duplicate_trace($trace, $bug, $comment);
 
52
    _check_duplicate_trace($trace, $bug, $comment);    
57
53
}
58
54
 
59
55
sub _check_duplicate_trace {
186
182
    # If this trace is higher quality than any other trace on the
187
183
    # bug, then we add the comment. Otherwise we just skip the
188
184
    # comment entirely.
189
 
    my $bug_traces = TraceParser::Trace->traces_on_bug($dup_to);
 
185
    my $bug_traces = Bugzilla::Extension::TraceParser::Trace->traces_on_bug($dup_to);
190
186
    my $higher_quality_traces;
191
187
    foreach my $t (@$bug_traces) {
192
188
        if ($t->{quality} >= $trace->{quality}) {
241
237
                     comment_added => $comment_added });
242
238
}
243
239
 
244
 
sub bug_update {
245
 
    my %params = @_;
246
 
    my ($bug, $timestamp) = @params{qw(bug timestamp)};
 
240
 
 
241
 
 
242
sub bug_end_of_update {
 
243
    my ($self, $args) = @_;
 
244
    
 
245
    my ($bug, $timestamp) = @$args{qw(bug timestamp)};
247
246
    return if !$bug->{added_comments};
248
247
    my $comments = Bugzilla::Bug::GetComments($bug->id, 'oldest_to_newest', 
249
248
                                              $bug->delta_ts, $timestamp, 1);
250
249
    foreach my $comment (@$comments) {
251
 
        my $data = TraceParser::Trace->parse_from_text($comment->{body});
 
250
        my $data = Bugzilla::Extension::TraceParser::Trace->parse_from_text(
 
251
            $comment->{body});
252
252
        next if !$data;
253
 
        TraceParser::Trace->create({ %$data, comment_id => $comment->{id} });
254
 
    }
 
253
        Bugzilla::Extension::TraceParser::Trace->create(
 
254
            { %$data, comment_id => $comment->{id} });
 
255
    }    
 
256
}
 
257
 
 
258
sub bug_format_comment {
 
259
    my ($self, $args) = @_;
 
260
 
 
261
    my ($text, $bug, $regexes, $comment) = @$args{qw(text bug regexes comment)};
 
262
    return if !$comment;
 
263
    my ($trace) = @{ Bugzilla::Extension::TraceParser::Trace->match(
 
264
                         { comment_id => $comment->{id} }) };
 
265
    return if !$trace;
 
266
 
 
267
    # $$text contains the wrapped text, and $comment contains the unwrapped
 
268
    # text. To find the trace that we want from the DB, we need to use the
 
269
    # unwrapped text. But to find the text that we need to replace, we
 
270
    # need to use the wrapped text.
 
271
    my $match_text;
 
272
    if ($comment->{already_wrapped}) {
 
273
        $match_text = $trace->text;
 
274
    }
 
275
    else {
 
276
        my $stacktrace = Bugzilla::Extension::TraceParser::Trace->stacktrace_from_text($$text);
 
277
        $match_text = $stacktrace->text;
 
278
    }
 
279
 
 
280
    $match_text = quotemeta($match_text);
 
281
    my $replacement;
 
282
    my $template = Bugzilla->template_inner;
 
283
    $template->process('trace/format.html.tmpl', { trace => $trace },
 
284
                       \$replacement)
 
285
      || ThrowTemplateError($template->error);
 
286
    # Make sure that replacements don't contain $1, $2, etc.
 
287
    $replacement =~ s{\$}{\\\$};
 
288
    push(@$regexes, { match => qr/$match_text/s, replace => $replacement });
 
289
}
 
290
 
 
291
sub db_schema_abstract_schema {
 
292
    my ($self, $args) = @_;
 
293
    
 
294
    
 
295
    
 
296
    my $schema = $args->{schema};
 
297
    $schema->{trace} = {
 
298
        FIELDS => [
 
299
            id          => {TYPE => 'MEDIUMSERIAL',  NOTNULL => 1, 
 
300
                            PRIMARYKEY => 1},
 
301
            comment_id  => {TYPE => 'INT3', NOTNULL => 1, 
 
302
                            REFERENCES => {TABLE  => 'longdescs',
 
303
                                           COLUMN => 'comment_id',
 
304
                                           DELETE => 'CASCADE'}},
 
305
            type        => {TYPE => 'varchar(255)', NOTNULL => 1},
 
306
            short_hash  => {TYPE => 'char(22)'},
 
307
            stack_hash  => {TYPE => 'char(22)'},
 
308
            trace_text  => {TYPE => 'LONGTEXT', NOTNULL => 1},
 
309
            quality     => {TYPE => 'real', NOTNULL => 1},
 
310
        ],
 
311
        INDEXES => [
 
312
            trace_short_hash_idx => ['short_hash'],
 
313
            trace_stack_hash_idx => ['stack_hash'],
 
314
            trace_comment_id_idx => {TYPE => 'UNIQUE', FIELDS => ['comment_id']},
 
315
        ],
 
316
    };
 
317
    
 
318
    $schema->{trace_dup} = {
 
319
        FIELDS => [
 
320
            hash      => {TYPE => 'char(22)', NOTNULL => 1},
 
321
            identical => {TYPE => 'BOOLEAN', NOTNULL => 1, DEFAULT => 0},
 
322
            bug_id    => {TYPE => 'INT3', NOTNULL => 1, 
 
323
                          REFERENCES => {TABLE  => 'bugs',
 
324
                                         COLUMN => 'bug_id'}},
 
325
        ],
 
326
        INDEXES => [
 
327
            trace_dup_hash_idx => {TYPE => 'UNIQUE', 
 
328
                                   FIELDS => [qw(hash identical)]},
 
329
            trace_bug_id_idx   => ['bug_id'],
 
330
        ],
 
331
    };
 
332
}
 
333
 
 
334
sub install_before_final_checks {
 
335
    my ($self, $args) = @_;
 
336
    
 
337
    if (!new Bugzilla::Group({ name => 'traceparser_edit' })) {
 
338
        Bugzilla::Group->create({
 
339
            name        => 'traceparser_edit',
 
340
            description => 'Can edit properties of traces',
 
341
            isbuggroup  => 0 });
 
342
    }
 
343
    
 
344
    add_setting('traceparser_show_traces',
 
345
                ['on', 'off'], 'off');
255
346
}
256
347
 
257
348
sub install_update_db {
273
364
    my $count = 1;
274
365
    my @traces;
275
366
    while (my ($comment_id, $text) = $sth->fetchrow_array) {
276
 
        my $trace = TraceParser::Trace->parse_from_text($text);
 
367
        my $trace = Bugzilla::Extension::TraceParser::Trace->parse_from_text($text);
277
368
        indicate_progress({ current => $count++, total => $total,
278
369
                            every => 100 });
279
370
        next if !$trace;
292
383
    $count = 1;
293
384
    $dbh->bz_start_transaction();
294
385
    while (my $trace = shift @traces) {
295
 
        TraceParser::Trace->create($trace);
 
386
        Bugzilla::Extension::TraceParser::Trace->create($trace);
296
387
        indicate_progress({ current => $count++, total => $total_traces,
297
388
                            every => 100 });
298
389
    }
299
390
    $dbh->bz_commit_transaction();
300
391
}
301
392
 
302
 
sub format_comment {
303
 
    my %params = @_;
304
 
    my ($text, $bug, $regexes, $comment) = @params{qw(text bug regexes comment)};
305
 
    return if !$comment;
306
 
    my ($trace) = @{ TraceParser::Trace->match({ comment_id => $comment->{id} }) };
307
 
    return if !$trace;
308
 
 
309
 
    # $$text contains the wrapped text, and $comment contains the unwrapped
310
 
    # text. To find the trace that we want from the DB, we need to use the
311
 
    # unwrapped text. But to find the text that we need to replace, we
312
 
    # need to use the wrapped text.
313
 
    my $match_text;
314
 
    if ($comment->{already_wrapped}) {
315
 
        $match_text = $trace->text;
316
 
    }
317
 
    else {
318
 
        my $stacktrace = TraceParser::Trace->stacktrace_from_text($$text);
319
 
        $match_text = $stacktrace->text;
320
 
    }
321
 
 
322
 
    $match_text = quotemeta($match_text);
323
 
    my $replacement;
324
 
    my $template = Bugzilla->template_inner;
325
 
    $template->process('trace/format.html.tmpl', { trace => $trace },
326
 
                       \$replacement)
327
 
      || ThrowTemplateError($template->error);
328
 
    # Make sure that replacements don't contain $1, $2, etc.
329
 
    $replacement =~ s{\$}{\\\$};
330
 
    push(@$regexes, { match => qr/$match_text/s, replace => $replacement });
331
 
}
332
 
 
333
 
sub page {
334
 
    my %params = @_;
335
 
    my ($vars, $page) = @params{qw(vars page_id)};
 
393
sub page_before_template {
 
394
    my ($self, $args) = @_;
 
395
    
 
396
    my ($vars, $page) = @$args{qw(vars page_id)};
336
397
    if ($page =~ /^trace\./) {
337
398
        _page_trace($vars);
338
399
    }
351
412
    my $user = Bugzilla->user;
352
413
 
353
414
    my $trace_id = $cgi->param('trace_id');
354
 
    my $trace = TraceParser::Trace->check({ id => $trace_id });
 
415
    my $trace = Bugzilla::Extension::TraceParser::Trace->check({ id => $trace_id });
355
416
    $trace->check_is_visible;
356
417
 
357
418
    my $action = $cgi->param('action') || '';
417
478
       GROUP BY short_hash ORDER BY trace_count DESC "
418
479
        . $dbh->sql_limit('?'), {Columns=>[1,2]}, $limit) };
419
480
 
420
 
    my $traces = TraceParser::Trace->new_from_list([keys %trace_count]);
 
481
    my $traces = Bugzilla::Extension::TraceParser::Trace->new_from_list([keys %trace_count]);
421
482
    @$traces = reverse sort { $trace_count{$a->id} <=> $trace_count{$b->id} } 
422
483
                            @$traces;
423
484
    $vars->{limit} = $limit;
430
491
    my $comment = { body      => scalar $cgi->param('comment'),
431
492
                    isprivate => scalar $cgi->param('isprivate'),
432
493
                  };
433
 
    my $trace = TraceParser::Trace->parse_from_text($comment->{body});
 
494
    my $trace = Bugzilla::Extension::TraceParser::Trace->parse_from_text($comment->{body});
434
495
    my $bug = Bugzilla::Bug->check(scalar $cgi->param('bug_id'));
435
496
    _handle_dup_to($trace, $bug, $comment, 'allow closed');
436
497
}
437
498
 
438
499
1;
 
500
 
 
501
__PACKAGE__->NAME;