Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(367)

Side by Side Diff: tools/presubmit.py

Issue 440026: Speed up presubmit cpplint checking by skipping unchanged files (Closed)
Patch Set: Minor corrections Created 11 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # 2 #
3 # Copyright 2008 the V8 project authors. All rights reserved. 3 # Copyright 2008 the V8 project authors. All rights reserved.
4 # Redistribution and use in source and binary forms, with or without 4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are 5 # modification, are permitted provided that the following conditions are
6 # met: 6 # met:
7 # 7 #
8 # * Redistributions of source code must retain the above copyright 8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer. 9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above 10 # * Redistributions in binary form must reproduce the above
(...skipping 10 matching lines...) Expand all
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 29
30 30
31 import md5
31 import optparse 32 import optparse
32 import os 33 import os
33 from os.path import abspath, join, dirname, basename, exists 34 from os.path import abspath, join, dirname, basename, exists
35 import pickle
34 import re 36 import re
35 import sys 37 import sys
36 import subprocess 38 import subprocess
37 39
38 # Disabled LINT rules and reason. 40 # Disabled LINT rules and reason.
39 # build/include_what_you_use: Started giving false positives for variables 41 # build/include_what_you_use: Started giving false positives for variables
40 # named "string" and "map" assuming that you needed to include STL headers. 42 # named "string" and "map" assuming that you needed to include STL headers.
41 43
42 ENABLED_LINT_RULES = """ 44 ENABLED_LINT_RULES = """
43 build/class 45 build/class
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 whitespace/labels 88 whitespace/labels
87 whitespace/line_length 89 whitespace/line_length
88 whitespace/newline 90 whitespace/newline
89 whitespace/operators 91 whitespace/operators
90 whitespace/parens 92 whitespace/parens
91 whitespace/tab 93 whitespace/tab
92 whitespace/todo 94 whitespace/todo
93 """.split() 95 """.split()
94 96
95 97
98 class FileContentsCache(object):
99
100 def __init__(self, sums_file_name):
101 self.sums = {}
102 self.sums_file_name = sums_file_name
103
104 def Load(self):
105 try:
106 sums_file = None
107 try:
108 sums_file = open(self.sums_file_name, 'r')
109 self.sums = pickle.load(sums_file)
110 except IOError:
111 # File might not exist, this is OK.
112 pass
113 finally:
114 if sums_file:
115 sums_file.close()
116
117 def Save(self):
118 try:
119 sums_file = open(self.sums_file_name, 'w')
120 pickle.dump(self.sums, sums_file)
121 finally:
122 sums_file.close()
123
124 def FilterUnchangedFiles(self, files):
125 changed_or_new = []
126 for file in files:
127 try:
128 handle = open(file, "r")
129 file_sum = md5.new(handle.read()).digest()
130 if not file in self.sums or self.sums[file] != file_sum:
131 changed_or_new.append(file)
132 self.sums[file] = file_sum
133 finally:
134 handle.close()
135 return changed_or_new
136
137 def RemoveFile(self, file):
138 if file in self.sums:
139 self.sums.pop(file)
140
141
96 class SourceFileProcessor(object): 142 class SourceFileProcessor(object):
97 """ 143 """
98 Utility class that can run through a directory structure, find all relevant 144 Utility class that can run through a directory structure, find all relevant
99 files and invoke a custom check on the files. 145 files and invoke a custom check on the files.
100 """ 146 """
101 147
102 def Run(self, path): 148 def Run(self, path):
103 all_files = [] 149 all_files = []
104 for file in self.GetPathsToSearch(): 150 for file in self.GetPathsToSearch():
105 all_files += self.FindFilesIn(join(path, file)) 151 all_files += self.FindFilesIn(join(path, file))
(...skipping 24 matching lines...) Expand all
130 """ 176 """
131 177
132 def IsRelevant(self, name): 178 def IsRelevant(self, name):
133 return name.endswith('.cc') or name.endswith('.h') 179 return name.endswith('.cc') or name.endswith('.h')
134 180
135 def IgnoreDir(self, name): 181 def IgnoreDir(self, name):
136 return (super(CppLintProcessor, self).IgnoreDir(name) 182 return (super(CppLintProcessor, self).IgnoreDir(name)
137 or (name == 'third_party')) 183 or (name == 'third_party'))
138 184
139 IGNORE_LINT = ['flag-definitions.h'] 185 IGNORE_LINT = ['flag-definitions.h']
140 186
141 def IgnoreFile(self, name): 187 def IgnoreFile(self, name):
142 return (super(CppLintProcessor, self).IgnoreFile(name) 188 return (super(CppLintProcessor, self).IgnoreFile(name)
143 or (name in CppLintProcessor.IGNORE_LINT)) 189 or (name in CppLintProcessor.IGNORE_LINT))
144 190
145 def GetPathsToSearch(self): 191 def GetPathsToSearch(self):
146 return ['src', 'public', 'samples', join('test', 'cctest')] 192 return ['src', 'public', 'samples', join('test', 'cctest')]
147 193
148 def ProcessFiles(self, files, path): 194 def ProcessFiles(self, files, path):
195 good_files_cache = FileContentsCache('.cpplint-cache')
196 good_files_cache.Load()
197 files = good_files_cache.FilterUnchangedFiles(files)
198 if len(files) == 0:
199 print 'No changes in files detected. Skipping cpplint check.'
200 return True
201
149 filt = '-,' + ",".join(['+' + n for n in ENABLED_LINT_RULES]) 202 filt = '-,' + ",".join(['+' + n for n in ENABLED_LINT_RULES])
150 command = ['cpplint.py', '--filter', filt] + join(files) 203 command = ['cpplint.py', '--filter', filt] + join(files)
151 local_cpplint = join(path, "tools", "cpplint.py") 204 local_cpplint = join(path, "tools", "cpplint.py")
152 if exists(local_cpplint): 205 if exists(local_cpplint):
153 command = ['python', local_cpplint, '--filter', filt] + join(files) 206 command = ['python', local_cpplint, '--filter', filt] + join(files)
154 process = subprocess.Popen(command) 207
155 return process.wait() == 0 208 process = subprocess.Popen(command, stderr=subprocess.PIPE)
209 LINT_ERROR_PATTERN = re.compile(r'^(.+)[:(]\d+[:)]')
210 while True:
211 out_line = process.stderr.readline()
212 if out_line == '' and process.poll() != None:
213 break
214 sys.stderr.write(out_line)
215 m = LINT_ERROR_PATTERN.match(out_line)
216 if m:
217 good_files_cache.RemoveFile(m.group(1))
218
219 good_files_cache.Save()
220 return process.returncode == 0
156 221
157 222
158 COPYRIGHT_HEADER_PATTERN = re.compile( 223 COPYRIGHT_HEADER_PATTERN = re.compile(
159 r'Copyright [\d-]*200[8-9] the V8 project authors. All rights reserved.') 224 r'Copyright [\d-]*200[8-9] the V8 project authors. All rights reserved.')
160 225
161 class SourceProcessor(SourceFileProcessor): 226 class SourceProcessor(SourceFileProcessor):
162 """ 227 """
163 Check that all files include a copyright notice. 228 Check that all files include a copyright notice.
164 """ 229 """
165 230
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
225 success = CppLintProcessor().Run(workspace) and success 290 success = CppLintProcessor().Run(workspace) and success
226 success = SourceProcessor().Run(workspace) and success 291 success = SourceProcessor().Run(workspace) and success
227 if success: 292 if success:
228 return 0 293 return 0
229 else: 294 else:
230 return 1 295 return 1
231 296
232 297
233 if __name__ == '__main__': 298 if __name__ == '__main__':
234 sys.exit(Main()) 299 sys.exit(Main())
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698