| Index: tools/presubmit.py
|
| diff --git a/tools/presubmit.py b/tools/presubmit.py
|
| index 5a99c2addabc39bedf73c1c90f551dd510089f46..3f27c001a1365c38311b101699d23bac31e9f701 100755
|
| --- a/tools/presubmit.py
|
| +++ b/tools/presubmit.py
|
| @@ -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(
|
|
|