Changeset 50547 in webkit


Ignore:
Timestamp:
Nov 4, 2009 11:07:00 PM (14 years ago)
Author:
eric@webkit.org
Message:

2009-11-04 Eric Seidel <eric@webkit.org>

Reviewed by David Kilzer.

svn-apply's fixChangeLogPatch function seems broken
https://bugs.webkit.org/show_bug.cgi?id=30683

Update fixChangeLogPatch to be able to handle patches which
don't start at line 1.
Add unit tests for svn-apply to scm_unittest.py.

  • Scripts/VCSUtils.pm:
  • Scripts/modules/scm_unittest.py:
Location:
trunk/WebKitTools
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebKitTools/ChangeLog

    r50525 r50547  
     12009-11-04  Eric Seidel  <eric@webkit.org>
     2
     3        Reviewed by David Kilzer.
     4
     5        svn-apply's fixChangeLogPatch function seems broken
     6        https://bugs.webkit.org/show_bug.cgi?id=30683
     7
     8        Update fixChangeLogPatch to be able to handle patches which
     9        don't start at line 1.
     10        Add unit tests for svn-apply to scm_unittest.py.
     11
     12        * Scripts/VCSUtils.pm:
     13        * Scripts/modules/scm_unittest.py:
     14
    1152009-11-04  Chris Fleizach  <cfleizach@apple.com>
    216
  • trunk/WebKitTools/Scripts/VCSUtils.pm

    r50318 r50547  
    356356}
    357357
     358# The diff(1) command is greedy when matching lines, so a new ChangeLog entry will
     359# have lines of context at the top of a patch when the existing entry has the same
     360# date and author as the new entry.  Alter the ChangeLog patch so
     361# that the added lines ("+") in the patch always start at the beginning of the
     362# patch and there are no initial lines of context.
    358363sub fixChangeLogPatch($)
    359364{
    360     my $patch = shift;
    361     my $contextLineCount = 3;
    362 
    363     return $patch if $patch !~ /\n@@ -1,(\d+) \+1,(\d+) @@\n( .*\n)+(\+.*\n)+( .*\n){$contextLineCount}$/m;
    364     my ($oldLineCount, $newLineCount) = ($1, $2);
    365     return $patch if $oldLineCount <= $contextLineCount;
    366 
    367     # The diff(1) command is greedy when matching lines, so a new ChangeLog entry will
    368     # have lines of context at the top of a patch when the existing entry has the same
    369     # date and author as the new entry.  This nifty loop alters a ChangeLog patch so
    370     # that the added lines ("+") in the patch always start at the beginning of the
    371     # patch and there are no initial lines of context.
    372     my $newPatch;
    373     my $lineCountInState = 0;
    374     my $oldContentLineCountReduction = $oldLineCount - $contextLineCount;
    375     my $newContentLineCountWithoutContext = $newLineCount - $oldLineCount - $oldContentLineCountReduction;
    376     my ($stateHeader, $statePreContext, $stateNewChanges, $statePostContext) = (1..4);
    377     my $state = $stateHeader;
    378     foreach my $line (split(/\n/, $patch)) {
    379         $lineCountInState++;
    380         if ($state == $stateHeader && $line =~ /^@@ -1,$oldLineCount \+1,$newLineCount @\@$/) {
    381             $line = "@@ -1,$contextLineCount +1," . ($newLineCount - $oldContentLineCountReduction) . " @@";
    382             $lineCountInState = 0;
    383             $state = $statePreContext;
    384         } elsif ($state == $statePreContext && substr($line, 0, 1) eq " ") {
    385             $line = "+" . substr($line, 1);
    386             if ($lineCountInState == $oldContentLineCountReduction) {
    387                 $lineCountInState = 0;
    388                 $state = $stateNewChanges;
     365    my $patch = shift; # $patch will only contain patch fragments for ChangeLog.
     366
     367    $patch =~ /(\r?\n)/;
     368    my $lineEnding = $1;
     369    my @patchLines = split(/$lineEnding/, $patch);
     370
     371    # e.g. 2009-06-03  Eric Seidel  <eric@webkit.org>
     372    my $dateLineRegexpString = '^\+(\d{4}-\d{2}-\d{2})' # Consume the leading '+' and the date.
     373                             . '\s+(.+)\s+' # Consume the name.
     374                             . '<([^<>]+)>$'; # And finally the email address.
     375
     376    # Figure out where the patch contents start and stop.
     377    my $patchHeaderIndex;
     378    my $firstContentIndex;
     379    my $trailingContextIndex;
     380    my $dateIndex;
     381    my $patchEndIndex = scalar(@patchLines);
     382    for (my $index = 0; $index < @patchLines; ++$index) {
     383        my $line = $patchLines[$index];
     384        if ($line =~ /^\@\@ -\d+,\d+ \+\d+,\d+ \@\@$/) { # e.g. @@ -1,5 +1,18 @@
     385            if ($patchHeaderIndex) {
     386                $patchEndIndex = $index; # We only bother to fix up the first patch fragment.
     387                last;
    389388            }
    390         } elsif ($state == $stateNewChanges && substr($line, 0, 1) eq "+") {
    391             # No changes to these lines
    392             if ($lineCountInState == $newContentLineCountWithoutContext) {
    393                 $lineCountInState = 0;
    394                 $state = $statePostContext;
    395             }
    396         } elsif ($state == $statePostContext) {
    397             if (substr($line, 0, 1) eq "+" && $lineCountInState <= $oldContentLineCountReduction) {
    398                 $line = " " . substr($line, 1);
    399             } elsif ($lineCountInState > $contextLineCount && substr($line, 0, 1) eq " ") {
    400                 next; # Discard
    401             }
     389            $patchHeaderIndex = $index;
    402390        }
    403         $newPatch .= $line . "\n";
    404     }
    405 
    406     return $newPatch;
    407 }
    408 
     391        $firstContentIndex = $index if ($patchHeaderIndex && !$firstContentIndex && $line =~ /^\+[^+]/); # Only match after finding patchHeaderIndex, otherwise we'd match "+++".
     392        $dateIndex = $index if ($line =~ /$dateLineRegexpString/);
     393        $trailingContextIndex = $index if ($firstContentIndex && !$trailingContextIndex && $line =~ /^ /);
     394    }
     395    my $contentLineCount = $trailingContextIndex - $firstContentIndex;
     396    my $trailingContextLineCount = $patchEndIndex - $trailingContextIndex;
     397
     398    # If we didn't find a date line in the content then this is not a patch we should try and fix.
     399    return $patch if (!$dateIndex);
     400
     401    # We only need to do anything if the date line is not the first content line.
     402    return $patch if ($dateIndex == $firstContentIndex);
     403
     404    # Write the new patch.
     405    my $totalNewContentLines = $contentLineCount + $trailingContextLineCount;
     406    $patchLines[$patchHeaderIndex] = "@@ -1,$trailingContextLineCount +1,$totalNewContentLines @@"; # Write a new header.
     407    my @repeatedLines = splice(@patchLines, $dateIndex, $trailingContextIndex - $dateIndex); # The date line and all the content after it that diff saw as repeated.
     408    splice(@patchLines, $firstContentIndex, 0, @repeatedLines); # Move the repeated content to the top.
     409    foreach my $line (@repeatedLines) {
     410        $line =~ s/^\+/ /;
     411    }
     412    splice(@patchLines, $trailingContextIndex, $patchEndIndex, @repeatedLines); # Replace trailing context with the repeated content.
     413    splice(@patchLines, $patchHeaderIndex + 1, $firstContentIndex - $patchHeaderIndex - 1); # Remove any leading context.
     414
     415    return join($lineEnding, @patchLines) . "\n"; # patch(1) expects an extra trailing newline.
     416}
    409417
    4104181;
  • trunk/WebKitTools/Scripts/modules/scm_unittest.py

    r49931 r50547  
    3636import unittest
    3737import urllib
     38
     39from datetime import date
    3840from modules.scm import detect_scm_system, SCM, ScriptError, CheckoutNeedsUpdate, ignore_error, commit_error_handler
    3941
     
    205207class SVNTest(SCMTest):
    206208
     209    @staticmethod
     210    def _set_date_and_reviewer(changelog_entry):
     211        # Joe Cool matches the reviewer set in SCMTest._create_patch
     212        changelog_entry = changelog_entry.replace('REVIEWER_HERE', 'Joe Cool')
     213        # svn-apply will update ChangeLog entries with today's date.
     214        return changelog_entry.replace('DATE_HERE', date.today().isoformat())
     215
     216    def test_svn_apply(self):
     217        first_entry = """2009-10-26  Eric Seidel  <eric@webkit.org>
     218
     219        Reviewed by Foo Bar.
     220
     221        Most awesome change ever.
     222
     223        * scm_unittest.py:
     224"""
     225        intermediate_entry = """2009-10-27  Eric Seidel  <eric@webkit.org>
     226
     227        Reviewed by Baz Bar.
     228
     229        A more awesomer change yet!
     230
     231        * scm_unittest.py:
     232"""
     233        one_line_overlap_patch = """Index: ChangeLog
     234===================================================================
     235--- ChangeLog   (revision 5)
     236+++ ChangeLog   (working copy)
     237@@ -1,5 +1,13 @@
     238 2009-10-26  Eric Seidel  <eric@webkit.org>
     239
     240+        Reviewed by NOBODY (OOPS!).
     241+
     242+        Second most awsome change ever.
     243+
     244+        * scm_unittest.py:
     245+
     246+2009-10-26  Eric Seidel  <eric@webkit.org>
     247+
     248         Reviewed by Foo Bar.
     249
     250         Most awesome change ever.
     251"""
     252        one_line_overlap_entry = """DATE_HERE  Eric Seidel  <eric@webkit.org>
     253
     254        Reviewed by REVIEWER_HERE.
     255
     256        Second most awsome change ever.
     257
     258        * scm_unittest.py:
     259"""
     260        two_line_overlap_patch = """Index: ChangeLog
     261===================================================================
     262--- ChangeLog   (revision 5)
     263+++ ChangeLog   (working copy)
     264@@ -2,6 +2,14 @@
     265
     266         Reviewed by Foo Bar.
     267
     268+        Second most awsome change ever.
     269+
     270+        * scm_unittest.py:
     271+
     272+2009-10-26  Eric Seidel  <eric@webkit.org>
     273+
     274+        Reviewed by Foo Bar.
     275+
     276         Most awesome change ever.
     277
     278         * scm_unittest.py:
     279"""
     280        two_line_overlap_entry = """DATE_HERE  Eric Seidel  <eric@webkit.org>
     281
     282        Reviewed by Foo Bar.
     283
     284        Second most awsome change ever.
     285
     286        * scm_unittest.py:
     287"""
     288        write_into_file_at_path('ChangeLog', first_entry)
     289        run(['svn', 'add', 'ChangeLog'])
     290        run(['svn', 'commit', '--quiet', '--message', 'ChangeLog commit'])
     291
     292        # Patch files were created against just 'first_entry'.
     293        # Add a second commit to make svn-apply have to apply the patches with fuzz.
     294        changelog_contents = "%s\n%s" % (intermediate_entry, first_entry)
     295        write_into_file_at_path('ChangeLog', changelog_contents)
     296        run(['svn', 'commit', '--quiet', '--message', 'Intermediate commit'])
     297
     298        self._setup_webkittools_scripts_symlink(self.scm)
     299        self.scm.apply_patch(self._create_patch(one_line_overlap_patch))
     300        expected_changelog_contents = "%s\n%s" % (self._set_date_and_reviewer(one_line_overlap_entry), changelog_contents)
     301        self.assertEquals(read_from_path('ChangeLog'), expected_changelog_contents)
     302
     303        self.scm.revert_files(['ChangeLog'])
     304        self.scm.apply_patch(self._create_patch(two_line_overlap_patch))
     305        expected_changelog_contents = "%s\n%s" % (self._set_date_and_reviewer(two_line_overlap_entry), changelog_contents)
     306        self.assertEquals(read_from_path('ChangeLog'), expected_changelog_contents)
     307
    207308    def setUp(self):
    208309        SVNTestRepository.setup(self)
Note: See TracChangeset for help on using the changeset viewer.