Changeset 52646 in webkit
- Timestamp:
- Dec 29, 2009 11:19:18 PM (14 years ago)
- Location:
- trunk/WebKitTools
- Files:
-
- 2 added
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebKitTools/ChangeLog
r52645 r52646 1 2009-12-29 Chris Jerdonek <chris.jerdonek@gmail.com> 2 3 Reviewed by David Kilzer. 4 5 Fixed a bug in fixChangeLogPatch, made it work correctly in 6 more circumstances, and added unit tests. 7 8 https://bugs.webkit.org/show_bug.cgi?id=32919 9 10 * Scripts/VCSUtils.pm: 11 Rewrote fixChangeLogPatch. 12 13 * Scripts/VCSUtils_unittest.pl: Added. 14 Added 7 unit tests for fixChangeLogPatch. 15 16 * Scripts/test-webkit-perl: Added. 17 Added test harness for unit tests of Perl code. 18 1 19 2009-12-29 Eric Seidel <eric@webkit.org> 2 20 -
trunk/WebKitTools/Scripts/VCSUtils.pm
r50863 r52646 1 1 # Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved. 2 # Copyright (C) 2009 Chris Jerdonek (chris.jerdonek@gmail.com) 2 3 # 3 4 # Redistribution and use in source and binary forms, with or without … … 357 358 } 358 359 359 # The diff(1) command is greedy when matching lines, so a new ChangeLog entry will 360 # have lines of context at the top of a patch when the existing entry has the same 361 # date and author as the new entry. Alter the ChangeLog patch so 362 # that the added lines ("+") in the patch always start at the beginning of the 363 # patch and there are no initial lines of context. 360 # If possible, returns a ChangeLog patch equivalent to the given one, 361 # but with the newest ChangeLog entry inserted at the top of the 362 # file -- i.e. no leading context and all lines starting with "+". 363 # 364 # If given a patch string not representable as a patch with the above 365 # properties, it returns the input back unchanged. 366 # 367 # WARNING: This subroutine can return an inequivalent patch string if 368 # both the beginning of the new ChangeLog file matches the beginning 369 # of the source ChangeLog, and the source beginning was modified. 370 # Otherwise, it is guaranteed to return an equivalent patch string, 371 # if it returns. 372 # 373 # Applying this subroutine to ChangeLog patches allows svn-apply to 374 # insert new ChangeLog entries at the top of the ChangeLog file. 375 # svn-apply uses patch with --fuzz=3 to do this. We need to apply 376 # this subroutine because the diff(1) command is greedy when matching 377 # lines. A new ChangeLog entry with the same date and author as the 378 # previous will match and cause the diff to have lines of starting 379 # context. 380 # 381 # This subroutine has unit tests in VCSUtils_unittest.pl. 364 382 sub fixChangeLogPatch($) 365 383 { … … 368 386 $patch =~ /(\r?\n)/; 369 387 my $lineEnding = $1; 370 my @patchLines = split(/$lineEnding/, $patch); 371 372 # e.g. 2009-06-03 Eric Seidel <eric@webkit.org> 373 my $dateLineRegexpString = '^\+(\d{4}-\d{2}-\d{2})' # Consume the leading '+' and the date. 374 . '\s+(.+)\s+' # Consume the name. 375 . '<([^<>]+)>$'; # And finally the email address. 376 377 # Figure out where the patch contents start and stop. 378 my $patchHeaderIndex; 379 my $firstContentIndex; 380 my $trailingContextIndex; 381 my $dateIndex; 382 my $patchEndIndex = scalar(@patchLines); 383 for (my $index = 0; $index < @patchLines; ++$index) { 384 my $line = $patchLines[$index]; 385 if ($line =~ /^\@\@ -\d+,\d+ \+\d+,\d+ \@\@$/) { # e.g. @@ -1,5 +1,18 @@ 386 if ($patchHeaderIndex) { 387 $patchEndIndex = $index; # We only bother to fix up the first patch fragment. 388 last; 389 } 390 $patchHeaderIndex = $index; 391 } 392 $firstContentIndex = $index if ($patchHeaderIndex && !$firstContentIndex && $line =~ /^\+[^+]/); # Only match after finding patchHeaderIndex, otherwise we'd match "+++". 393 $dateIndex = $index if ($line =~ /$dateLineRegexpString/); 394 $trailingContextIndex = $index if ($firstContentIndex && !$trailingContextIndex && $line =~ /^ /); 395 } 396 my $contentLineCount = $trailingContextIndex - $firstContentIndex; 397 my $trailingContextLineCount = $patchEndIndex - $trailingContextIndex; 398 399 # If we didn't find a date line in the content then this is not a patch we should try and fix. 400 return $patch if (!$dateIndex); 401 402 # We only need to do anything if the date line is not the first content line. 403 return $patch if ($dateIndex == $firstContentIndex); 404 405 # Write the new patch. 406 my $totalNewContentLines = $contentLineCount + $trailingContextLineCount; 407 $patchLines[$patchHeaderIndex] = "@@ -1,$trailingContextLineCount +1,$totalNewContentLines @@"; # Write a new header. 408 my @repeatedLines = splice(@patchLines, $dateIndex, $trailingContextIndex - $dateIndex); # The date line and all the content after it that diff saw as repeated. 409 splice(@patchLines, $firstContentIndex, 0, @repeatedLines); # Move the repeated content to the top. 410 foreach my $line (@repeatedLines) { 411 $line =~ s/^\+/ /; 412 } 413 splice(@patchLines, $trailingContextIndex, $patchEndIndex, @repeatedLines); # Replace trailing context with the repeated content. 414 splice(@patchLines, $patchHeaderIndex + 1, $firstContentIndex - $patchHeaderIndex - 1); # Remove any leading context. 415 416 return join($lineEnding, @patchLines) . "\n"; # patch(1) expects an extra trailing newline. 388 my @lines = split(/$lineEnding/, $patch); 389 390 my $i = 0; # We reuse the same index throughout. 391 392 # Skip to beginning of first chunk. 393 for (; $i < @lines; ++$i) { 394 if (substr($lines[$i], 0, 1) eq "@") { 395 last; 396 } 397 } 398 my $chunkStartIndex = ++$i; 399 400 # Optimization: do not process if new lines already begin the chunk. 401 if (substr($lines[$i], 0, 1) eq "+") { 402 return $patch; 403 } 404 405 # Skip to first line of newly added ChangeLog entry. 406 # For example, +2009-06-03 Eric Seidel <eric@webkit.org> 407 my $dateStartRegEx = '^\+(\d{4}-\d{2}-\d{2})' # leading "+" and date 408 . '\s+(.+)\s+' # name 409 . '<([^<>]+)>$'; # e-mail address 410 411 for (; $i < @lines; ++$i) { 412 my $line = $lines[$i]; 413 my $firstChar = substr($line, 0, 1); 414 if ($line =~ /$dateStartRegEx/) { 415 last; 416 } elsif ($firstChar eq " " or $firstChar eq "+") { 417 next; 418 } 419 return $patch; # Do not change if, for example, "-" or "@" found. 420 } 421 if ($i >= @lines) { 422 return $patch; # Do not change if date not found. 423 } 424 my $dateStartIndex = $i; 425 426 # Rewrite overlapping lines to lead with " ". 427 my @overlappingLines = (); # These will include a leading "+". 428 for (; $i < @lines; ++$i) { 429 my $line = $lines[$i]; 430 if (substr($line, 0, 1) ne "+") { 431 last; 432 } 433 push(@overlappingLines, $line); 434 $lines[$i] = " " . substr($line, 1); 435 } 436 437 # Remove excess ending context, if necessary. 438 my $shouldTrimContext = 1; 439 for (; $i < @lines; ++$i) { 440 my $firstChar = substr($lines[$i], 0, 1); 441 if ($firstChar eq " ") { 442 next; 443 } elsif ($firstChar eq "@") { 444 last; 445 } 446 $shouldTrimContext = 0; # For example, if "+" or "-" encountered. 447 last; 448 } 449 my $deletedLineCount = 0; 450 if ($shouldTrimContext) { # Also occurs if end of file reached. 451 splice(@lines, $i - @overlappingLines, @overlappingLines); 452 $deletedLineCount = @overlappingLines; 453 } 454 455 # Work backwards, shifting overlapping lines towards front 456 # while checking that patch stays equivalent. 457 for ($i = $dateStartIndex - 1; $i >= $chunkStartIndex; --$i) { 458 my $line = $lines[$i]; 459 if (substr($line, 0, 1) ne " ") { 460 next; 461 } 462 my $text = substr($line, 1); 463 my $newLine = pop(@overlappingLines); 464 if ($text ne substr($newLine, 1)) { 465 return $patch; # Unexpected difference. 466 } 467 $lines[$i] = "+$text"; 468 } 469 470 # Finish moving whatever overlapping lines remain, and update 471 # the initial chunk range. 472 my $chunkRangeRegEx = '^\@\@ -(\d+),(\d+) \+\d+,(\d+) \@\@$'; # e.g. @@ -2,6 +2,18 @@ 473 if ($lines[$chunkStartIndex - 1] !~ /$chunkRangeRegEx/) { 474 # FIXME: Handle errors differently from ChangeLog files that 475 # are okay but should not be altered. That way we can find out 476 # if improvements to the script ever become necessary. 477 return $patch; # Error: unexpected patch string format. 478 } 479 my $skippedFirstLineCount = $1 - 1; 480 my $oldSourceLineCount = $2; 481 my $oldTargetLineCount = $3; 482 483 if (@overlappingLines != $skippedFirstLineCount) { 484 # This can happen, for example, when deliberately inserting 485 # a new ChangeLog entry earlier in the file. 486 return $patch; 487 } 488 # If @overlappingLines > 0, this is where we make use of the 489 # assumption that the beginning of the source file was not modified. 490 splice(@lines, $chunkStartIndex, 0, @overlappingLines); 491 492 my $sourceLineCount = $oldSourceLineCount + @overlappingLines - $deletedLineCount; 493 my $targetLineCount = $oldTargetLineCount + @overlappingLines - $deletedLineCount; 494 $lines[$chunkStartIndex - 1] = "@@ -1,$sourceLineCount +1,$targetLineCount @@"; 495 496 return join($lineEnding, @lines) . "\n"; # patch(1) expects an extra trailing newline. 417 497 } 418 498
Note: See TracChangeset
for help on using the changeset viewer.