X-Git-Url: http://code.vuplus.com/gitweb/?p=vuplus_webkit;a=blobdiff_plain;f=Websites%2Fbugs.webkit.org%2FBugzilla%2FAttachment%2FPatchReader.pm;fp=Websites%2Fbugs.webkit.org%2FBugzilla%2FAttachment%2FPatchReader.pm;h=cfc7610f4029c5e4348081f812c2b3dc16abbfba;hp=0000000000000000000000000000000000000000;hb=186b2535c234ccc42a8c27998f11be6f718f604f;hpb=1c567be6144228b511852e3cab689fc41b052875 diff --git a/Websites/bugs.webkit.org/Bugzilla/Attachment/PatchReader.pm b/Websites/bugs.webkit.org/Bugzilla/Attachment/PatchReader.pm new file mode 100644 index 0000000..cfc7610 --- /dev/null +++ b/Websites/bugs.webkit.org/Bugzilla/Attachment/PatchReader.pm @@ -0,0 +1,295 @@ +# -*- Mode: perl; indent-tabs-mode: nil -*- +# +# 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. +# +# The Original Code is the Bugzilla Bug Tracking System. +# +# Contributor(s): John Keiser +# Frédéric Buclin + +use strict; + +package Bugzilla::Attachment::PatchReader; + +use Bugzilla::Error; +use Bugzilla::Attachment; +use Bugzilla::Util; + +sub process_diff { + my ($attachment, $format, $context) = @_; + my $dbh = Bugzilla->dbh; + my $cgi = Bugzilla->cgi; + my $lc = Bugzilla->localconfig; + my $vars = {}; + + my ($reader, $last_reader) = setup_patch_readers(undef, $context); + + if ($format eq 'raw') { + require PatchReader::DiffPrinter::raw; + $last_reader->sends_data_to(new PatchReader::DiffPrinter::raw()); + # Actually print out the patch. + print $cgi->header(-type => 'text/plain', + -expires => '+3M'); + 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_id)}; + # 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; + } + } + } + + $vars->{'bugid'} = $attachment->bug_id; + $vars->{'attachid'} = $attachment->id; + $vars->{'description'} = $attachment->description; + $vars->{'other_patches'} = \@other_patches; + + setup_template_patch_reader($last_reader, $format, $context, $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, $context) = @_; + my $cgi = Bugzilla->cgi; + my $lc = Bugzilla->localconfig; + my $vars = {}; + + # 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. + $ENV{'PATH'} = $lc->{diffpath}; + open my $interdiff_fh, "$lc->{interdiffbin} $old_filename $new_filename|"; + binmode $interdiff_fh; + my ($reader, $last_reader) = setup_patch_readers("", $context); + + if ($format eq 'raw') { + require PatchReader::DiffPrinter::raw; + $last_reader->sends_data_to(new PatchReader::DiffPrinter::raw()); + # Actually print out the patch. + print $cgi->header(-type => 'text/plain', + -expires => '+3M'); + disable_utf8(); + } + else { + # In case the HTML page is displayed with the UTF-8 encoding. + binmode $interdiff_fh, ':utf8' if Bugzilla->params->{'utf8'}; + + $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($last_reader, $format, $context, $vars); + } + $reader->iterate_fh($interdiff_fh, 'interdiff #' . $old_attachment->id . + ' #' . $new_attachment->id); + close $interdiff_fh; + $ENV{'PATH'} = ''; + + # Delete temporary files. + unlink($old_filename) or warn "Could not unlink $old_filename: $!"; + unlink($new_filename) or warn "Could not unlink $new_filename: $!"; +} + +###################### +# Internal routines +###################### + +sub get_unified_diff { + my ($attachment, $format) = @_; + + # Bring in the modules we need. + require PatchReader::Raw; + require PatchReader::FixPatchRoot; + 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; + + # Fixes patch root (makes canonical if possible). + if (Bugzilla->params->{'cvsroot'}) { + my $fix_patch_root = + new PatchReader::FixPatchRoot(Bugzilla->params->{'cvsroot'}); + $last_reader->sends_data_to($fix_patch_root); + $last_reader = $fix_patch_root; + } + + # 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; + + # Iterate! + $reader->iterate_string($attachment->id, $attachment->data); + + return ($filename, $patch_info_grabber->patch_info()->{files}); +} + +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 ($old_file_list->{$file}{old_revision} ne + $new_file_list->{$file}{old_revision}) + { + return 'interdiff2'; + } + } + return undef; +} + +sub setup_patch_readers { + my ($diff_root, $context) = @_; + + # Parameters: + # format=raw|html + # context=patch|file|0-n + # collapsed=0|1 + # headers=0|1 + + # Define the patch readers. + # The reader that reads the patch in (whatever its format). + require PatchReader::Raw; + my $reader = new PatchReader::Raw; + my $last_reader = $reader; + # Fix the patch root if we have a cvs root. + if (Bugzilla->params->{'cvsroot'}) { + require PatchReader::FixPatchRoot; + $last_reader->sends_data_to(new PatchReader::FixPatchRoot(Bugzilla->params->{'cvsroot'})); + $last_reader->sends_data_to->diff_root($diff_root) if defined($diff_root); + $last_reader = $last_reader->sends_data_to; + } + + # Add in cvs context if we have the necessary info to do it + if ($context ne 'patch' && Bugzilla->localconfig->{cvsbin} + && Bugzilla->params->{'cvsroot_get'}) + { + require PatchReader::AddCVSContext; + # We need to set $cvsbin as global, because PatchReader::CVSClient + # needs it in order to find 'cvs'. + $main::cvsbin = Bugzilla->localconfig->{cvsbin}; + $last_reader->sends_data_to( + new PatchReader::AddCVSContext($context, Bugzilla->params->{'cvsroot_get'})); + $last_reader = $last_reader->sends_data_to; + } + + return ($reader, $last_reader); +} + +sub setup_template_patch_reader { + my ($last_reader, $format, $context, $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'); + $vars->{'context'} = $context; + $vars->{'do_context'} = Bugzilla->localconfig->{cvsbin} + && Bugzilla->params->{'cvsroot_get'} && !$vars->{'newid'}; + + # Print everything out. + print $cgi->header(-type => 'text/html', + -expires => '+3M'); + + $last_reader->sends_data_to(new PatchReader::DiffPrinter::template($template, + "attachment/diff-header.$format.tmpl", + "attachment/diff-file.$format.tmpl", + "attachment/diff-footer.$format.tmpl", + { %{$vars}, + bonsai_url => Bugzilla->params->{'bonsai_url'}, + lxr_url => Bugzilla->params->{'lxr_url'}, + lxr_root => Bugzilla->params->{'lxr_root'}, + })); +} + +1; + +__END__