aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Bugzilla/Attachment/PatchReader.pm')
-rw-r--r--Bugzilla/Attachment/PatchReader.pm499
1 files changed, 257 insertions, 242 deletions
diff --git a/Bugzilla/Attachment/PatchReader.pm b/Bugzilla/Attachment/PatchReader.pm
index d0e221220..01ed51518 100644
--- a/Bugzilla/Attachment/PatchReader.pm
+++ b/Bugzilla/Attachment/PatchReader.pm
@@ -23,184 +23,199 @@ use Bugzilla::Util;
use constant PERLIO_IS_ENABLED => $Config{useperlio};
sub process_diff {
- my ($attachment, $format) = @_;
- my $dbh = Bugzilla->dbh;
- my $cgi = Bugzilla->cgi;
- my $lc = Bugzilla->localconfig;
- my $vars = {};
-
- require PatchReader::Raw;
- my $reader = new PatchReader::Raw;
-
- if ($format eq 'raw') {
- require PatchReader::DiffPrinter::raw;
- $reader->sends_data_to(new PatchReader::DiffPrinter::raw());
- # Actually print out the patch.
- print $cgi->header(-type => 'text/plain');
- disable_utf8();
- $reader->iterate_string('Attachment ' . $attachment->id, $attachment->data);
- }
- else {
- my @other_patches = ();
- if ($lc->{interdiffbin} && $lc->{diffpath}) {
- # Get the list of attachments that the user can view in this bug.
- my @attachments =
- @{Bugzilla::Attachment->get_attachments_by_bug($attachment->bug)};
- # Extract patches only.
- @attachments = grep {$_->ispatch == 1} @attachments;
- # We want them sorted from newer to older.
- @attachments = sort { $b->id <=> $a->id } @attachments;
-
- # Ignore the current patch, but select the one right before it
- # chronologically.
- my $select_next_patch = 0;
- foreach my $attach (@attachments) {
- if ($attach->id == $attachment->id) {
- $select_next_patch = 1;
- }
- else {
- push(@other_patches, { 'id' => $attach->id,
- 'desc' => $attach->description,
- 'selected' => $select_next_patch });
- $select_next_patch = 0;
- }
- }
- }
+ my ($attachment, $format) = @_;
+ my $dbh = Bugzilla->dbh;
+ my $cgi = Bugzilla->cgi;
+ my $lc = Bugzilla->localconfig;
+ my $vars = {};
- $vars->{'bugid'} = $attachment->bug_id;
- $vars->{'attachid'} = $attachment->id;
- $vars->{'description'} = $attachment->description;
- $vars->{'other_patches'} = \@other_patches;
-
- setup_template_patch_reader($reader, $vars);
- # The patch is going to be displayed in a HTML page and if the utf8
- # param is enabled, we have to encode attachment data as utf8.
- if (Bugzilla->params->{'utf8'}) {
- $attachment->data; # Populate ->{data}
- utf8::decode($attachment->{data});
- }
- $reader->iterate_string('Attachment ' . $attachment->id, $attachment->data);
- }
-}
-
-sub process_interdiff {
- my ($old_attachment, $new_attachment, $format) = @_;
- my $cgi = Bugzilla->cgi;
- my $lc = Bugzilla->localconfig;
- my $vars = {};
-
- require PatchReader::Raw;
-
- # Encode attachment data as utf8 if it's going to be displayed in a HTML
- # page using the UTF-8 encoding.
- if ($format ne 'raw' && Bugzilla->params->{'utf8'}) {
- $old_attachment->data; # Populate ->{data}
- utf8::decode($old_attachment->{data});
- $new_attachment->data; # Populate ->{data}
- utf8::decode($new_attachment->{data});
- }
-
- # Get old patch data.
- my ($old_filename, $old_file_list) = get_unified_diff($old_attachment, $format);
- # Get new patch data.
- my ($new_filename, $new_file_list) = get_unified_diff($new_attachment, $format);
-
- my $warning = warn_if_interdiff_might_fail($old_file_list, $new_file_list);
-
- # Send through interdiff, send output directly to template.
- # Must hack path so that interdiff will work.
- local $ENV{'PATH'} = $lc->{diffpath};
-
- # Open the interdiff pipe, reading from both STDOUT and STDERR
- # To avoid deadlocks, we have to read the entire output from all handles
- my ($stdout, $stderr) = ('', '');
- my ($pid, $interdiff_stdout, $interdiff_stderr, $use_select);
- if ($ENV{MOD_PERL}) {
- require Apache2::RequestUtil;
- require Apache2::SubProcess;
- my $request = Apache2::RequestUtil->request;
- (undef, $interdiff_stdout, $interdiff_stderr) = $request->spawn_proc_prog(
- $lc->{interdiffbin}, [$old_filename, $new_filename]
- );
- $use_select = !PERLIO_IS_ENABLED;
- } else {
- $interdiff_stderr = gensym;
- $pid = open3(gensym, $interdiff_stdout, $interdiff_stderr,
- $lc->{interdiffbin}, $old_filename, $new_filename);
- $use_select = 1;
- }
+ require PatchReader::Raw;
+ my $reader = new PatchReader::Raw;
- if ($format ne 'raw' && Bugzilla->params->{'utf8'}) {
- binmode $interdiff_stdout, ':utf8';
- binmode $interdiff_stderr, ':utf8';
- } else {
- binmode $interdiff_stdout;
- binmode $interdiff_stderr;
- }
-
- if ($use_select) {
- my $select = IO::Select->new();
- $select->add($interdiff_stdout, $interdiff_stderr);
- while (my @handles = $select->can_read) {
- foreach my $handle (@handles) {
- my $line = <$handle>;
- if (!defined $line) {
- $select->remove($handle);
- next;
- }
- if ($handle == $interdiff_stdout) {
- $stdout .= $line;
- } else {
- $stderr .= $line;
- }
+ if ($format eq 'raw') {
+ require PatchReader::DiffPrinter::raw;
+ $reader->sends_data_to(new PatchReader::DiffPrinter::raw());
+
+ # Actually print out the patch.
+ print $cgi->header(-type => 'text/plain');
+ disable_utf8();
+ $reader->iterate_string('Attachment ' . $attachment->id, $attachment->data);
+ }
+ else {
+ my @other_patches = ();
+ if ($lc->{interdiffbin} && $lc->{diffpath}) {
+
+ # Get the list of attachments that the user can view in this bug.
+ my @attachments
+ = @{Bugzilla::Attachment->get_attachments_by_bug($attachment->bug)};
+
+ # Extract patches only.
+ @attachments = grep { $_->ispatch == 1 } @attachments;
+
+ # We want them sorted from newer to older.
+ @attachments = sort { $b->id <=> $a->id } @attachments;
+
+ # Ignore the current patch, but select the one right before it
+ # chronologically.
+ my $select_next_patch = 0;
+ foreach my $attach (@attachments) {
+ if ($attach->id == $attachment->id) {
+ $select_next_patch = 1;
+ }
+ else {
+ push(
+ @other_patches,
+ {
+ 'id' => $attach->id,
+ 'desc' => $attach->description,
+ 'selected' => $select_next_patch
}
+ );
+ $select_next_patch = 0;
}
- waitpid($pid, 0) if $pid;
-
- } else {
- local $/ = undef;
- $stdout = <$interdiff_stdout>;
- $stdout //= '';
- $stderr = <$interdiff_stderr>;
- $stderr //= '';
+ }
}
- close($interdiff_stdout),
- close($interdiff_stderr);
+ $vars->{'bugid'} = $attachment->bug_id;
+ $vars->{'attachid'} = $attachment->id;
+ $vars->{'description'} = $attachment->description;
+ $vars->{'other_patches'} = \@other_patches;
- # Tidy up
- unlink($old_filename) or warn "Could not unlink $old_filename: $!";
- unlink($new_filename) or warn "Could not unlink $new_filename: $!";
+ setup_template_patch_reader($reader, $vars);
- # Any output on STDERR means interdiff failed to full process the patches.
- # Interdiff's error messages are generic and not useful to end users, so we
- # show a generic failure message.
- if ($stderr) {
- warn($stderr);
- $warning = 'interdiff3';
+ # The patch is going to be displayed in a HTML page and if the utf8
+ # param is enabled, we have to encode attachment data as utf8.
+ if (Bugzilla->params->{'utf8'}) {
+ $attachment->data; # Populate ->{data}
+ utf8::decode($attachment->{data});
}
+ $reader->iterate_string('Attachment ' . $attachment->id, $attachment->data);
+ }
+}
- my $reader = new PatchReader::Raw;
-
- if ($format eq 'raw') {
- require PatchReader::DiffPrinter::raw;
- $reader->sends_data_to(new PatchReader::DiffPrinter::raw());
- # Actually print out the patch.
- print $cgi->header(-type => 'text/plain');
- disable_utf8();
- }
- else {
- $vars->{'warning'} = $warning if $warning;
- $vars->{'bugid'} = $new_attachment->bug_id;
- $vars->{'oldid'} = $old_attachment->id;
- $vars->{'old_desc'} = $old_attachment->description;
- $vars->{'newid'} = $new_attachment->id;
- $vars->{'new_desc'} = $new_attachment->description;
-
- setup_template_patch_reader($reader, $vars);
+sub process_interdiff {
+ my ($old_attachment, $new_attachment, $format) = @_;
+ my $cgi = Bugzilla->cgi;
+ my $lc = Bugzilla->localconfig;
+ my $vars = {};
+
+ require PatchReader::Raw;
+
+ # Encode attachment data as utf8 if it's going to be displayed in a HTML
+ # page using the UTF-8 encoding.
+ if ($format ne 'raw' && Bugzilla->params->{'utf8'}) {
+ $old_attachment->data; # Populate ->{data}
+ utf8::decode($old_attachment->{data});
+ $new_attachment->data; # Populate ->{data}
+ utf8::decode($new_attachment->{data});
+ }
+
+ # Get old patch data.
+ my ($old_filename, $old_file_list) = get_unified_diff($old_attachment, $format);
+
+ # Get new patch data.
+ my ($new_filename, $new_file_list) = get_unified_diff($new_attachment, $format);
+
+ my $warning = warn_if_interdiff_might_fail($old_file_list, $new_file_list);
+
+ # Send through interdiff, send output directly to template.
+ # Must hack path so that interdiff will work.
+ local $ENV{'PATH'} = $lc->{diffpath};
+
+ # Open the interdiff pipe, reading from both STDOUT and STDERR
+ # To avoid deadlocks, we have to read the entire output from all handles
+ my ($stdout, $stderr) = ('', '');
+ my ($pid, $interdiff_stdout, $interdiff_stderr, $use_select);
+ if ($ENV{MOD_PERL}) {
+ require Apache2::RequestUtil;
+ require Apache2::SubProcess;
+ my $request = Apache2::RequestUtil->request;
+ (undef, $interdiff_stdout, $interdiff_stderr)
+ = $request->spawn_proc_prog($lc->{interdiffbin},
+ [$old_filename, $new_filename]);
+ $use_select = !PERLIO_IS_ENABLED;
+ }
+ else {
+ $interdiff_stderr = gensym;
+ $pid = open3(gensym, $interdiff_stdout, $interdiff_stderr, $lc->{interdiffbin},
+ $old_filename, $new_filename);
+ $use_select = 1;
+ }
+
+ if ($format ne 'raw' && Bugzilla->params->{'utf8'}) {
+ binmode $interdiff_stdout, ':utf8';
+ binmode $interdiff_stderr, ':utf8';
+ }
+ else {
+ binmode $interdiff_stdout;
+ binmode $interdiff_stderr;
+ }
+
+ if ($use_select) {
+ my $select = IO::Select->new();
+ $select->add($interdiff_stdout, $interdiff_stderr);
+ while (my @handles = $select->can_read) {
+ foreach my $handle (@handles) {
+ my $line = <$handle>;
+ if (!defined $line) {
+ $select->remove($handle);
+ next;
+ }
+ if ($handle == $interdiff_stdout) {
+ $stdout .= $line;
+ }
+ else {
+ $stderr .= $line;
+ }
+ }
}
- $reader->iterate_string('interdiff #' . $old_attachment->id .
- ' #' . $new_attachment->id, $stdout);
+ waitpid($pid, 0) if $pid;
+
+ }
+ else {
+ local $/ = undef;
+ $stdout = <$interdiff_stdout>;
+ $stdout //= '';
+ $stderr = <$interdiff_stderr>;
+ $stderr //= '';
+ }
+
+ close($interdiff_stdout), close($interdiff_stderr);
+
+ # Tidy up
+ unlink($old_filename) or warn "Could not unlink $old_filename: $!";
+ unlink($new_filename) or warn "Could not unlink $new_filename: $!";
+
+ # Any output on STDERR means interdiff failed to full process the patches.
+ # Interdiff's error messages are generic and not useful to end users, so we
+ # show a generic failure message.
+ if ($stderr) {
+ warn($stderr);
+ $warning = 'interdiff3';
+ }
+
+ my $reader = new PatchReader::Raw;
+
+ if ($format eq 'raw') {
+ require PatchReader::DiffPrinter::raw;
+ $reader->sends_data_to(new PatchReader::DiffPrinter::raw());
+
+ # Actually print out the patch.
+ print $cgi->header(-type => 'text/plain');
+ disable_utf8();
+ }
+ else {
+ $vars->{'warning'} = $warning if $warning;
+ $vars->{'bugid'} = $new_attachment->bug_id;
+ $vars->{'oldid'} = $old_attachment->id;
+ $vars->{'old_desc'} = $old_attachment->description;
+ $vars->{'newid'} = $new_attachment->id;
+ $vars->{'new_desc'} = $new_attachment->description;
+
+ setup_template_patch_reader($reader, $vars);
+ }
+ $reader->iterate_string(
+ 'interdiff #' . $old_attachment->id . ' #' . $new_attachment->id, $stdout);
}
######################
@@ -208,92 +223,92 @@ sub process_interdiff {
######################
sub get_unified_diff {
- my ($attachment, $format) = @_;
+ my ($attachment, $format) = @_;
- # Bring in the modules we need.
- require PatchReader::Raw;
- require PatchReader::DiffPrinter::raw;
- require PatchReader::PatchInfoGrabber;
- require File::Temp;
-
- $attachment->ispatch
- || ThrowCodeError('must_be_patch', { 'attach_id' => $attachment->id });
-
- # Reads in the patch, converting to unified diff in a temp file.
- my $reader = new PatchReader::Raw;
- my $last_reader = $reader;
-
- # Grabs the patch file info.
- my $patch_info_grabber = new PatchReader::PatchInfoGrabber();
- $last_reader->sends_data_to($patch_info_grabber);
- $last_reader = $patch_info_grabber;
-
- # Prints out to temporary file.
- my ($fh, $filename) = File::Temp::tempfile();
- if ($format ne 'raw' && Bugzilla->params->{'utf8'}) {
- # The HTML page will be displayed with the UTF-8 encoding.
- binmode $fh, ':utf8';
- }
- my $raw_printer = new PatchReader::DiffPrinter::raw($fh);
- $last_reader->sends_data_to($raw_printer);
- $last_reader = $raw_printer;
+ # Bring in the modules we need.
+ require PatchReader::Raw;
+ require PatchReader::DiffPrinter::raw;
+ require PatchReader::PatchInfoGrabber;
+ require File::Temp;
- # Iterate!
- $reader->iterate_string($attachment->id, $attachment->data);
+ $attachment->ispatch
+ || ThrowCodeError('must_be_patch', {'attach_id' => $attachment->id});
- return ($filename, $patch_info_grabber->patch_info()->{files});
-}
+ # Reads in the patch, converting to unified diff in a temp file.
+ my $reader = new PatchReader::Raw;
+ my $last_reader = $reader;
-sub warn_if_interdiff_might_fail {
- my ($old_file_list, $new_file_list) = @_;
+ # Grabs the patch file info.
+ my $patch_info_grabber = new PatchReader::PatchInfoGrabber();
+ $last_reader->sends_data_to($patch_info_grabber);
+ $last_reader = $patch_info_grabber;
- # Verify that the list of files diffed is the same.
- my @old_files = sort keys %{$old_file_list};
- my @new_files = sort keys %{$new_file_list};
- if (@old_files != @new_files
- || join(' ', @old_files) ne join(' ', @new_files))
- {
- return 'interdiff1';
- }
+ # Prints out to temporary file.
+ my ($fh, $filename) = File::Temp::tempfile();
+ if ($format ne 'raw' && Bugzilla->params->{'utf8'}) {
- # Verify that the revisions in the files are the same.
- foreach my $file (keys %{$old_file_list}) {
- if (exists $old_file_list->{$file}{old_revision}
- && exists $new_file_list->{$file}{old_revision}
- && $old_file_list->{$file}{old_revision} ne
- $new_file_list->{$file}{old_revision})
- {
- return 'interdiff2';
- }
- }
- return undef;
-}
+ # The HTML page will be displayed with the UTF-8 encoding.
+ binmode $fh, ':utf8';
+ }
+ my $raw_printer = new PatchReader::DiffPrinter::raw($fh);
+ $last_reader->sends_data_to($raw_printer);
+ $last_reader = $raw_printer;
-sub setup_template_patch_reader {
- my ($last_reader, $vars) = @_;
- my $cgi = Bugzilla->cgi;
- my $template = Bugzilla->template;
+ # Iterate!
+ $reader->iterate_string($attachment->id, $attachment->data);
- require PatchReader::DiffPrinter::template;
+ return ($filename, $patch_info_grabber->patch_info()->{files});
+}
- # Define the vars for templates.
- if (defined $cgi->param('headers')) {
- $vars->{'headers'} = $cgi->param('headers');
- }
- else {
- $vars->{'headers'} = 1;
+sub warn_if_interdiff_might_fail {
+ my ($old_file_list, $new_file_list) = @_;
+
+ # Verify that the list of files diffed is the same.
+ my @old_files = sort keys %{$old_file_list};
+ my @new_files = sort keys %{$new_file_list};
+ if (@old_files != @new_files || join(' ', @old_files) ne join(' ', @new_files))
+ {
+ return 'interdiff1';
+ }
+
+ # Verify that the revisions in the files are the same.
+ foreach my $file (keys %{$old_file_list}) {
+ if ( exists $old_file_list->{$file}{old_revision}
+ && exists $new_file_list->{$file}{old_revision}
+ && $old_file_list->{$file}{old_revision} ne
+ $new_file_list->{$file}{old_revision})
+ {
+ return 'interdiff2';
}
+ }
+ return undef;
+}
- $vars->{'collapsed'} = $cgi->param('collapsed');
-
- # Print everything out.
- print $cgi->header(-type => 'text/html');
-
- $last_reader->sends_data_to(new PatchReader::DiffPrinter::template($template,
- 'attachment/diff-header.html.tmpl',
- 'attachment/diff-file.html.tmpl',
- 'attachment/diff-footer.html.tmpl',
- $vars));
+sub setup_template_patch_reader {
+ my ($last_reader, $vars) = @_;
+ my $cgi = Bugzilla->cgi;
+ my $template = Bugzilla->template;
+
+ require PatchReader::DiffPrinter::template;
+
+ # Define the vars for templates.
+ if (defined $cgi->param('headers')) {
+ $vars->{'headers'} = $cgi->param('headers');
+ }
+ else {
+ $vars->{'headers'} = 1;
+ }
+
+ $vars->{'collapsed'} = $cgi->param('collapsed');
+
+ # Print everything out.
+ print $cgi->header(-type => 'text/html');
+
+ $last_reader->sends_data_to(new PatchReader::DiffPrinter::template(
+ $template, 'attachment/diff-header.html.tmpl',
+ 'attachment/diff-file.html.tmpl', 'attachment/diff-footer.html.tmpl',
+ $vars
+ ));
}
1;