A cache of MD5 sums of source file contents is now maintained. Cpplint is only invoked for new, changed, and files containing errors from the past lint check run.

As a result, repetitive presubmit checks now run in a blink of an eye, so we can include it as an obligatory pre-submit check to avoid frequent CB breakages on lint errors.

Review URL: http://codereview.chromium.org/440026

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@3368 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mikhail.naganov@gmail.com 2009-11-26 10:17:03 +00:00
parent 25c5637e34
commit f2f00d0d09

View File

@ -28,9 +28,11 @@
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
import md5
import optparse
import os
from os.path import abspath, join, dirname, basename, exists
import pickle
import re
import sys
import subprocess
@ -93,6 +95,50 @@ whitespace/todo
""".split()
class FileContentsCache(object):
def __init__(self, sums_file_name):
self.sums = {}
self.sums_file_name = sums_file_name
def Load(self):
try:
sums_file = None
try:
sums_file = open(self.sums_file_name, 'r')
self.sums = pickle.load(sums_file)
except IOError:
# File might not exist, this is OK.
pass
finally:
if sums_file:
sums_file.close()
def Save(self):
try:
sums_file = open(self.sums_file_name, 'w')
pickle.dump(self.sums, sums_file)
finally:
sums_file.close()
def FilterUnchangedFiles(self, files):
changed_or_new = []
for file in files:
try:
handle = open(file, "r")
file_sum = md5.new(handle.read()).digest()
if not file in self.sums or self.sums[file] != file_sum:
changed_or_new.append(file)
self.sums[file] = file_sum
finally:
handle.close()
return changed_or_new
def RemoveFile(self, file):
if file in self.sums:
self.sums.pop(file)
class SourceFileProcessor(object):
"""
Utility class that can run through a directory structure, find all relevant
@ -137,7 +183,7 @@ class CppLintProcessor(SourceFileProcessor):
or (name == 'third_party'))
IGNORE_LINT = ['flag-definitions.h']
def IgnoreFile(self, name):
return (super(CppLintProcessor, self).IgnoreFile(name)
or (name in CppLintProcessor.IGNORE_LINT))
@ -146,13 +192,32 @@ class CppLintProcessor(SourceFileProcessor):
return ['src', 'public', 'samples', join('test', 'cctest')]
def ProcessFiles(self, files, path):
good_files_cache = FileContentsCache('.cpplint-cache')
good_files_cache.Load()
files = good_files_cache.FilterUnchangedFiles(files)
if len(files) == 0:
print 'No changes in files detected. Skipping cpplint check.'
return True
filt = '-,' + ",".join(['+' + n for n in ENABLED_LINT_RULES])
command = ['cpplint.py', '--filter', filt] + join(files)
local_cpplint = join(path, "tools", "cpplint.py")
if exists(local_cpplint):
command = ['python', local_cpplint, '--filter', filt] + join(files)
process = subprocess.Popen(command)
return process.wait() == 0
process = subprocess.Popen(command, stderr=subprocess.PIPE)
LINT_ERROR_PATTERN = re.compile(r'^(.+)[:(]\d+[:)]')
while True:
out_line = process.stderr.readline()
if out_line == '' and process.poll() != None:
break
sys.stderr.write(out_line)
m = LINT_ERROR_PATTERN.match(out_line)
if m:
good_files_cache.RemoveFile(m.group(1))
good_files_cache.Save()
return process.returncode == 0
COPYRIGHT_HEADER_PATTERN = re.compile(