WebKitTools:
[WebKit-https.git] / WebKitTools / Scripts / svn-create-patch
1 #!/usr/bin/perl -w
2
3 # Copyright (C) 2005, 2006 Apple Computer, Inc.  All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
7 # are met:
8 #
9 # 1.  Redistributions of source code must retain the above copyright
10 #     notice, this list of conditions and the following disclaimer. 
11 # 2.  Redistributions in binary form must reproduce the above copyright
12 #     notice, this list of conditions and the following disclaimer in the
13 #     documentation and/or other materials provided with the distribution. 
14 # 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 #     its contributors may be used to endorse or promote products derived
16 #     from this software without specific prior written permission. 
17 #
18 # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 # Simplified and improved "svn diff" script for WebKit Open Source Project, used to make patches.
30
31 # Differences from standard "svn diff":
32 #
33 #   Uses the real diff, not svn's built-in diff.
34 #   Always passes "-p" to diff so it will try to include function names.
35 #   Handles binary files (encoded as a base64 chunk of text).
36 #   Sorts the diffs alphabetically by text files, then binary files.
37 #
38 # Missing features:
39 #
40 #   Handle moved files.
41
42 use strict;
43
44 use Config;
45 use Cwd;
46 use File::Basename;
47 use File::Spec;
48 use File::stat;
49 use Getopt::Long;
50 use MIME::Base64;
51 use POSIX qw(:errno_h);
52 use Time::gmtime;
53
54 my $startDir = getcwd();
55 my %paths;
56
57 # Create list of paths to diff.
58 if (!@ARGV) {
59     $paths{"."} = 1;
60 } else {
61     for my $file (@ARGV) {
62         die "can't handle absolute paths like \"$file\"\n" if File::Spec->file_name_is_absolute($file);
63         die "can't handle empty string path\n" if $file eq "";
64         die "can't handle path with single quote in the name like \"$file\"\n" if $file =~ /'/; # ' (keep Xcode syntax highlighting happy)
65
66         my $untouchedFile = $file;
67
68         $file = canonicalizePath($file);
69
70         die "can't handle paths with .. like \"$untouchedFile\"\n" if $file =~ m|/\.\./|;
71
72         $paths{$file} = 1;
73     }
74
75     if ($paths{"."}) {
76         %paths = ();
77         $paths{"."} = 1;
78     } else {
79         # Remove any paths that also have a parent listed.
80         for my $path (keys %paths) {
81             for (my $parent = dirname($path); $parent ne '.'; $parent = dirname($parent)) {
82                 if ($paths{$parent}) {
83                     delete $paths{$path};
84                     last;
85                 }
86             }
87         }
88     }
89 }
90
91 # Generate a list of files requiring diffs
92 my %textFiles;
93 my %binaryFiles;
94 for my $path (keys %paths) {
95     generateFileList($path, \%textFiles, \%binaryFiles);
96 }
97
98 # Generate the diff for text files, then binary files, for easy reviewing
99 for my $file (sort keys %textFiles) {
100     generateDiff($file);
101 }
102 for my $file (sort keys %binaryFiles) {
103     generateDiff($file);
104 }
105
106 exit 0;
107
108
109 sub canonicalizePath
110 {
111     my ($file) = @_;
112
113     # Remove extra slashes and '.' directories in path
114     $file = File::Spec->canonpath($file);
115
116     # Remove '..' directories in path
117     my @dirs = ();
118     foreach my $dir (File::Spec->splitdir($file)) {
119         if ($dir eq '..' && $#dirs >= 0 && $dirs[$#dirs] ne '..') {
120             pop(@dirs);
121         } else {
122             push(@dirs, $dir);
123         }
124     }
125     return ($#dirs >= 0) ? File::Spec->catdir(@dirs) : ".";
126 }
127
128 sub generateDiff
129 {
130     my ($file) = @_;
131     my $errors = "";
132     my $isBinary;
133     my $lastLine;
134     open DIFF, "svn diff --diff-cmd diff -x -uNp '$file' |" or die;
135     while (<DIFF>) {
136         $isBinary = 1 if (/^Cannot display: file marked as a binary type\.$/);
137         print;
138         $lastLine = $_;
139     }
140     close DIFF;
141     print "\n" if ($isBinary && $lastLine =~ m/\S+/);
142     outputBinaryContent($file) if ($isBinary);
143     print STDERR $errors;
144 }
145
146 sub generateFileList
147 {
148     my ($path, $textFiles, $binaryFiles) = @_;
149     my $indexPath;
150     my $isBinary;
151     open DIFF, "svn diff --diff-cmd diff -x -uNp '$path' |" or die;
152     while (<DIFF>) {
153         if (/^Index: (.*)/) {
154             my $newIndexPath = $1;
155             if ($indexPath) {
156                 if ($isBinary) {
157                     $binaryFiles->{$indexPath} = 1;
158                 } else {
159                     $textFiles->{$indexPath} = 1;
160                 }
161             }
162             $indexPath = $newIndexPath;
163             $isBinary = 0;
164         }
165         if (/^Cannot display: file marked as a binary type\.$/) {
166             $isBinary = 1;
167         }
168     }
169     close DIFF;
170     # Handle last patch
171     if ($indexPath) {
172         if ($isBinary) {
173             $binaryFiles->{$indexPath} = 1;
174         } else {
175             $textFiles->{$indexPath} = 1;
176         }
177     }
178 }
179
180 sub outputBinaryContent
181 {
182     my ($path) = @_;
183     # Deletion
184     return if (! -e $path);
185     # Addition or Modification
186     my $buffer;
187     open BINARY, $path  or die;
188     while (read(BINARY, $buffer, 60*57)) {
189         print encode_base64($buffer);
190     }
191     close BINARY;
192     print "\n";
193 }
194