summaryrefslogtreecommitdiffstats
path: root/WebKitTools/Scripts/VCSUtils.pm
diff options
context:
space:
mode:
Diffstat (limited to 'WebKitTools/Scripts/VCSUtils.pm')
-rw-r--r--WebKitTools/Scripts/VCSUtils.pm137
1 files changed, 134 insertions, 3 deletions
diff --git a/WebKitTools/Scripts/VCSUtils.pm b/WebKitTools/Scripts/VCSUtils.pm
index 6ec12c9..e1e0bc2 100644
--- a/WebKitTools/Scripts/VCSUtils.pm
+++ b/WebKitTools/Scripts/VCSUtils.pm
@@ -40,10 +40,13 @@ BEGIN {
$VERSION = 1.00;
@ISA = qw(Exporter);
@EXPORT = qw(
+ &canonicalizePath
&chdirReturningRelativePath
&determineSVNRoot
&determineVCSRoot
+ &fixChangeLogPatch
&gitBranch
+ &gitdiff2svndiff
&isGit
&isGitBranchBuild
&isGitDirectory
@@ -51,8 +54,10 @@ BEGIN {
&isSVNDirectory
&isSVNVersion16OrNewer
&makeFilePathRelative
+ &normalizePath
&pathRelativeToSVNRepositoryRootForPath
&svnRevisionForDirectory
+ &svnStatus
);
%EXPORT_TAGS = ( );
@EXPORT_OK = ();
@@ -70,7 +75,7 @@ my $svnVersion;
sub isGitDirectory($)
{
my ($dir) = @_;
- return system("cd $dir && git rev-parse > /dev/null 2>&1") == 0;
+ return system("cd $dir && git rev-parse > " . File::Spec->devnull() . " 2>&1") == 0;
}
sub isGit()
@@ -159,7 +164,6 @@ sub determineGitRoot()
sub determineSVNRoot()
{
- my $devNull = File::Spec->devnull();
my $last = '';
my $path = '.';
my $parent = '..';
@@ -169,7 +173,7 @@ sub determineSVNRoot()
my $thisRoot;
my $thisUUID;
# Ignore error messages in case we've run past the root of the checkout.
- open INFO, "svn info '$path' 2> $devNull |" or die;
+ open INFO, "svn info '$path' 2> " . File::Spec->devnull() . " |" or die;
while (<INFO>) {
if (/^Repository Root: (.+)/) {
$thisRoot = $1;
@@ -268,4 +272,131 @@ sub makeFilePathRelative($)
return $gitRoot . $path;
}
+sub normalizePath($)
+{
+ my ($path) = @_;
+ $path =~ s/\\/\//g;
+ return $path;
+}
+
+sub canonicalizePath($)
+{
+ my ($file) = @_;
+
+ # Remove extra slashes and '.' directories in path
+ $file = File::Spec->canonpath($file);
+
+ # Remove '..' directories in path
+ my @dirs = ();
+ foreach my $dir (File::Spec->splitdir($file)) {
+ if ($dir eq '..' && $#dirs >= 0 && $dirs[$#dirs] ne '..') {
+ pop(@dirs);
+ } else {
+ push(@dirs, $dir);
+ }
+ }
+ return ($#dirs >= 0) ? File::Spec->catdir(@dirs) : ".";
+}
+
+sub svnStatus($)
+{
+ my ($fullPath) = @_;
+ my $svnStatus;
+ open SVN, "svn status --non-interactive --non-recursive '$fullPath' |" or die;
+ if (-d $fullPath) {
+ # When running "svn stat" on a directory, we can't assume that only one
+ # status will be returned (since any files with a status below the
+ # directory will be returned), and we can't assume that the directory will
+ # be first (since any files with unknown status will be listed first).
+ my $normalizedFullPath = File::Spec->catdir(File::Spec->splitdir($fullPath));
+ while (<SVN>) {
+ # Input may use a different EOL sequence than $/, so avoid chomp.
+ $_ = removeEOL($_);
+ my $normalizedStatPath = File::Spec->catdir(File::Spec->splitdir(substr($_, 7)));
+ if ($normalizedFullPath eq $normalizedStatPath) {
+ $svnStatus = "$_\n";
+ last;
+ }
+ }
+ # Read the rest of the svn command output to avoid a broken pipe warning.
+ local $/ = undef;
+ <SVN>;
+ }
+ else {
+ # Files will have only one status returned.
+ $svnStatus = removeEOL(<SVN>) . "\n";
+ }
+ close SVN;
+ return $svnStatus;
+}
+
+sub gitdiff2svndiff($)
+{
+ $_ = shift @_;
+ if (m#^diff --git a/(.+) b/(.+)#) {
+ return "Index: $1";
+ } elsif (m/^new file.*/) {
+ return "";
+ } elsif (m#^index [0-9a-f]{7}\.\.[0-9a-f]{7} [0-9]{6}#) {
+ return "===================================================================";
+ } elsif (m#^--- a/(.+)#) {
+ return "--- $1";
+ } elsif (m#^\+\+\+ b/(.+)#) {
+ return "+++ $1";
+ }
+ return $_;
+}
+
+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;
+}
+
+
1;