WebKitTools:
authorddkilzer <ddkilzer@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Jul 2006 16:15:02 +0000 (16:15 +0000)
committerddkilzer <ddkilzer@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 12 Jul 2006 16:15:02 +0000 (16:15 +0000)
        Reviewed by Darin.

        - fix http://bugzilla.opendarwin.org/show_bug.cgi?id=9848
          Teach svn-create-patch and friends to fix ChangeLog patches

        * Scripts/svn-apply: Added fixChangeLogPatch() and invoked it in the proper place.
        * Scripts/svn-create-patch: Ditto.
        * Scripts/svn-unapply: Ditto.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@15393 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebKitTools/ChangeLog
WebKitTools/Scripts/svn-apply
WebKitTools/Scripts/svn-create-patch
WebKitTools/Scripts/svn-unapply

index d751c317166052de4905b473c29b6b5a00d4f0b8..bd560a49428e5829bc7d6acdfd704b8386c1f6fa 100644 (file)
@@ -1,3 +1,14 @@
+2006-07-12  David Kilzer  <ddkilzer@kilzer.net>
+
+        Reviewed by Darin.
+
+        - fix http://bugzilla.opendarwin.org/show_bug.cgi?id=9848
+          Teach svn-create-patch and friends to fix ChangeLog patches
+
+        * Scripts/svn-apply: Added fixChangeLogPatch() and invoked it in the proper place.
+        * Scripts/svn-create-patch: Ditto.
+        * Scripts/svn-unapply: Ditto.
+
 2006-07-12  Mark Rowe  <opendarwin.org@bdash.net.nz>
 
         Reviewed by ggaren.
index e1f1463b70d703acd085f37cae77b1464fa40753..d17d672fc7a7e773b96d42d741e7baa3eb4743aa 100755 (executable)
@@ -65,6 +65,7 @@ use POSIX qw(strftime);
 
 sub addDirectoriesIfNeeded($);
 sub applyPatch($$;$);
+sub fixChangeLogPatch($);
 sub handleBinaryChange($$);
 sub isDirectoryEmptyForRemoval($);
 sub patch($);
@@ -173,6 +174,57 @@ sub applyPatch($$;$)
     close PATCH;
 }
 
+sub fixChangeLogPatch($)
+{
+    my $patch = shift;
+    my $contextLineCount = 3;
+
+    return $patch if $patch !~ /\n@@ -1,(\d+) \+1,(\d+) @@\n( .*\n)+(\+.*\n)+( .*\n){$contextLineCount}$/m;
+    my ($oldLineCount, $newLineCount) = ($1, $2);
+    return $patch if $oldLineCount <= $contextLineCount;
+
+    # The diff(1) command is greedy when matching lines, so a new ChangeLog entry will
+    # have lines of context at the top of a patch when the existing entry has the same
+    # date and author as the new entry.  This nifty loop alters a ChangeLog patch so
+    # that the added lines ("+") in the patch always start at the beginning of the
+    # patch and there are no initial lines of context.
+    my $newPatch;
+    my $lineCountInState = 0;
+    my $oldContentLineCountReduction = $oldLineCount - $contextLineCount;
+    my $newContentLineCountWithoutContext = $newLineCount - $oldLineCount - $oldContentLineCountReduction;
+    my ($stateHeader, $statePreContext, $stateNewChanges, $statePostContext) = (1..4);
+    my $state = $stateHeader;
+    foreach my $line (split(/\n/, $patch)) {
+        $lineCountInState++;
+        if ($state == $stateHeader && $line =~ /^@@ -1,$oldLineCount \+1,$newLineCount @\@$/) {
+            $line = "@@ -1,$contextLineCount +1," . ($newLineCount - $oldContentLineCountReduction) . " @@";
+            $lineCountInState = 0;
+            $state = $statePreContext;
+        } elsif ($state == $statePreContext && substr($line, 0, 1) eq " ") {
+            $line = "+" . substr($line, 1);
+            if ($lineCountInState == $oldContentLineCountReduction) {
+                $lineCountInState = 0;
+                $state = $stateNewChanges;
+            }
+        } elsif ($state == $stateNewChanges && substr($line, 0, 1) eq "+") {
+            # No changes to these lines
+            if ($lineCountInState == $newContentLineCountWithoutContext) {
+                $lineCountInState = 0;
+                $state = $statePostContext;
+            }
+        } elsif ($state == $statePostContext) {
+            if (substr($line, 0, 1) eq "+" && $lineCountInState <= $oldContentLineCountReduction) {
+                $line = " " . substr($line, 1);
+            } elsif ($lineCountInState > $contextLineCount && substr($line, 0, 1) eq " ") {
+                next; # Discard
+            }
+        }
+        $newPatch .= $line . "\n";
+    }
+
+    return $newPatch;
+}
+
 sub handleBinaryChange($$)
 {
     my ($fullPath, $contents) = @_;
@@ -234,7 +286,7 @@ sub patch($)
         # Standard patch, patch tool can handle this.
         if (basename($fullPath) eq "ChangeLog") {
             my $changeLogDotOrigExisted = -f "${fullPath}.orig";
-            applyPatch(setChangeLogDate($patch), $fullPath, ["--fuzz=3"]);
+            applyPatch(setChangeLogDate(fixChangeLogPatch($patch)), $fullPath, ["--fuzz=3"]);
             unlink("${fullPath}.orig") if (! $changeLogDotOrigExisted);
         } else {
             applyPatch($patch, $fullPath);
index 016051542070a084f4698bcceb1e4b0603fdc6b0..f8c13787163e1e57e77e8c0a7dfff680be6a549a 100755 (executable)
@@ -53,6 +53,7 @@ use POSIX qw(:errno_h);
 use Time::gmtime;
 
 sub canonicalizePath($);
+sub fixChangeLogPatch($);
 sub generateDiff($);
 sub generateFileList($\%\%);
 sub numericcmp($$);
@@ -106,21 +107,75 @@ sub canonicalizePath($)
     return ($#dirs >= 0) ? File::Spec->catdir(@dirs) : ".";
 }
 
+sub fixChangeLogPatch($)
+{
+    my $patch = shift;
+    my $contextLineCount = 3;
+
+    return $patch if $patch !~ /\n@@ -1,(\d+) \+1,(\d+) @@\n( .*\n)+(\+.*\n)+( .*\n){$contextLineCount}$/m;
+    my ($oldLineCount, $newLineCount) = ($1, $2);
+    return $patch if $oldLineCount <= $contextLineCount;
+
+    # The diff(1) command is greedy when matching lines, so a new ChangeLog entry will
+    # have lines of context at the top of a patch when the existing entry has the same
+    # date and author as the new entry.  This nifty loop alters a ChangeLog patch so
+    # that the added lines ("+") in the patch always start at the beginning of the
+    # patch and there are no initial lines of context.
+    my $newPatch;
+    my $lineCountInState = 0;
+    my $oldContentLineCountReduction = $oldLineCount - $contextLineCount;
+    my $newContentLineCountWithoutContext = $newLineCount - $oldLineCount - $oldContentLineCountReduction;
+    my ($stateHeader, $statePreContext, $stateNewChanges, $statePostContext) = (1..4);
+    my $state = $stateHeader;
+    foreach my $line (split(/\n/, $patch)) {
+        $lineCountInState++;
+        if ($state == $stateHeader && $line =~ /^@@ -1,$oldLineCount \+1,$newLineCount @\@$/) {
+            $line = "@@ -1,$contextLineCount +1," . ($newLineCount - $oldContentLineCountReduction) . " @@";
+            $lineCountInState = 0;
+            $state = $statePreContext;
+        } elsif ($state == $statePreContext && substr($line, 0, 1) eq " ") {
+            $line = "+" . substr($line, 1);
+            if ($lineCountInState == $oldContentLineCountReduction) {
+                $lineCountInState = 0;
+                $state = $stateNewChanges;
+            }
+        } elsif ($state == $stateNewChanges && substr($line, 0, 1) eq "+") {
+            # No changes to these lines
+            if ($lineCountInState == $newContentLineCountWithoutContext) {
+                $lineCountInState = 0;
+                $state = $statePostContext;
+            }
+        } elsif ($state == $statePostContext) {
+            if (substr($line, 0, 1) eq "+" && $lineCountInState <= $oldContentLineCountReduction) {
+                $line = " " . substr($line, 1);
+            } elsif ($lineCountInState > $contextLineCount && substr($line, 0, 1) eq " ") {
+                next; # Discard
+            }
+        }
+        $newPatch .= $line . "\n";
+    }
+
+    return $newPatch;
+}
+
 sub generateDiff($)
 {
     my ($file) = @_;
     my $errors = "";
     my $isBinary;
-    my $lastLine;
+    my $patch;
     open DIFF, "svn diff --diff-cmd diff -x -uNp '$file' |" or die;
     while (<DIFF>) {
         $isBinary = 1 if (/^Cannot display: file marked as a binary type\.$/);
-        print;
-        $lastLine = $_;
+        $patch .= $_;
     }
     close DIFF;
-    print "\n" if ($isBinary && $lastLine =~ m/\S+/);
-    outputBinaryContent($file) if ($isBinary);
+    $patch = fixChangeLogPatch($patch) if basename($file) eq "ChangeLog";
+    print $patch;
+    if ($isBinary) {
+        print "\n" if $patch =~ m/\n\S+$/m;
+        outputBinaryContent($file);
+    }
     print STDERR $errors;
 }
 
index 00d31161d81e031ffd856636a347a5488e4b3aba..5dfc77f6c2f23b11cf7a63dca2a6546ca29a088e 100755 (executable)
@@ -60,6 +60,7 @@ use File::Basename;
 use File::Spec;
 use Getopt::Long;
 
+sub fixChangeLogPatch($);
 sub patch($);
 sub revertDirectories();
 sub svnStatus($);
@@ -102,6 +103,57 @@ revertDirectories();
 
 exit 0;
 
+sub fixChangeLogPatch($)
+{
+    my $patch = shift;
+    my $contextLineCount = 3;
+
+    return $patch if $patch !~ /\n@@ -1,(\d+) \+1,(\d+) @@\n( .*\n)+(\+.*\n)+( .*\n){$contextLineCount}$/m;
+    my ($oldLineCount, $newLineCount) = ($1, $2);
+    return $patch if $oldLineCount <= $contextLineCount;
+
+    # The diff(1) command is greedy when matching lines, so a new ChangeLog entry will
+    # have lines of context at the top of a patch when the existing entry has the same
+    # date and author as the new entry.  This nifty loop alters a ChangeLog patch so
+    # that the added lines ("+") in the patch always start at the beginning of the
+    # patch and there are no initial lines of context.
+    my $newPatch;
+    my $lineCountInState = 0;
+    my $oldContentLineCountReduction = $oldLineCount - $contextLineCount;
+    my $newContentLineCountWithoutContext = $newLineCount - $oldLineCount - $oldContentLineCountReduction;
+    my ($stateHeader, $statePreContext, $stateNewChanges, $statePostContext) = (1..4);
+    my $state = $stateHeader;
+    foreach my $line (split(/\n/, $patch)) {
+        $lineCountInState++;
+        if ($state == $stateHeader && $line =~ /^@@ -1,$oldLineCount \+1,$newLineCount @\@$/) {
+            $line = "@@ -1,$contextLineCount +1," . ($newLineCount - $oldContentLineCountReduction) . " @@";
+            $lineCountInState = 0;
+            $state = $statePreContext;
+        } elsif ($state == $statePreContext && substr($line, 0, 1) eq " ") {
+            $line = "+" . substr($line, 1);
+            if ($lineCountInState == $oldContentLineCountReduction) {
+                $lineCountInState = 0;
+                $state = $stateNewChanges;
+            }
+        } elsif ($state == $stateNewChanges && substr($line, 0, 1) eq "+") {
+            # No changes to these lines
+            if ($lineCountInState == $newContentLineCountWithoutContext) {
+                $lineCountInState = 0;
+                $state = $statePostContext;
+            }
+        } elsif ($state == $statePostContext) {
+            if (substr($line, 0, 1) eq "+" && $lineCountInState <= $oldContentLineCountReduction) {
+                $line = " " . substr($line, 1);
+            } elsif ($lineCountInState > $contextLineCount && substr($line, 0, 1) eq " ") {
+                next; # Discard
+            }
+        }
+        $newPatch .= $line . "\n";
+    }
+
+    return $newPatch;
+}
+
 sub patch($)
 {
     my ($patch) = @_;
@@ -123,7 +175,7 @@ sub patch($)
         # Standard patch, patch tool can handle this.
         if (basename($fullPath) eq "ChangeLog") {
             my $changeLogDotOrigExisted = -f "${fullPath}.orig";
-            unapplyPatch(unsetChangeLogDate($fullPath, $patch), $fullPath, ["--fuzz=3"]);
+            unapplyPatch(unsetChangeLogDate($fullPath, fixChangeLogPatch($patch)), $fullPath, ["--fuzz=3"]);
             unlink("${fullPath}.orig") if (! $changeLogDotOrigExisted);
         } else {
             unapplyPatch($patch, $fullPath);