Revision: 3368
Author: [email protected]
Date: Thu Nov 26 02:17:03 2009
Log: 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
http://code.google.com/p/v8/source/detail?r=3368

Modified:
  /branches/bleeding_edge/tools/presubmit.py

=======================================
--- /branches/bleeding_edge/tools/presubmit.py  Thu Nov 12 04:11:40 2009
+++ /branches/bleeding_edge/tools/presubmit.py  Thu Nov 26 02:17:03 2009
@@ -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 @@
  """.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 @@
                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 @@
      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(

-- 
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev

Reply via email to