1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#!/usr/bin/env python 2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# 33ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch# Copyright 2012 the V8 project authors. All rights reserved. 4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# Redistribution and use in source and binary forms, with or without 5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# modification, are permitted provided that the following conditions are 6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# met: 7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# 8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# * Redistributions of source code must retain the above copyright 9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# notice, this list of conditions and the following disclaimer. 10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# * Redistributions in binary form must reproduce the above 11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# copyright notice, this list of conditions and the following 12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# disclaimer in the documentation and/or other materials provided 13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# with the distribution. 14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# * Neither the name of Google Inc. nor the names of its 15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# contributors may be used to endorse or promote products derived 16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# from this software without specific prior written permission. 17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# 18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 30bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdochtry: 31bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch import hashlib 32bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch md5er = hashlib.md5 33bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdochexcept ImportError, e: 34bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch import md5 35bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch md5er = md5.new 36bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch 37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockimport optparse 39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockimport os 40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfrom os.path import abspath, join, dirname, basename, exists 41d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockimport pickle 42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockimport re 43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockimport sys 44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockimport subprocess 453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochimport multiprocessing 46589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdochfrom subprocess import PIPE 47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# Disabled LINT rules and reason. 49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# build/include_what_you_use: Started giving false positives for variables 50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# named "string" and "map" assuming that you needed to include STL headers. 51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockENABLED_LINT_RULES = """ 53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbuild/class 54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbuild/deprecated 55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbuild/endif_comment 56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbuild/forward_decl 57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbuild/include_order 58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbuild/printf_format 59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockbuild/storage_class 60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blocklegal/copyright 61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockreadability/boost 62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockreadability/braces 63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockreadability/casting 64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockreadability/check 65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockreadability/constructors 66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockreadability/fn_size 67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockreadability/function 68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockreadability/multiline_comment 69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockreadability/multiline_string 70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockreadability/streams 71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockreadability/todo 72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockreadability/utf8 73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockruntime/arrays 74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockruntime/casting 75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockruntime/deprecated_fn 76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockruntime/explicit 77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockruntime/int 78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockruntime/memset 79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockruntime/mutex 80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockruntime/nonconf 81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockruntime/printf 82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockruntime/printf_format 83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockruntime/references 84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockruntime/rtti 85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockruntime/sizeof 86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockruntime/string 87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockruntime/virtual 88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockruntime/vlog 89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockwhitespace/blank_line 90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockwhitespace/braces 91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockwhitespace/comma 92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockwhitespace/comments 93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockwhitespace/ending_newline 94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockwhitespace/indent 95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockwhitespace/labels 96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockwhitespace/line_length 97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockwhitespace/newline 98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockwhitespace/operators 99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockwhitespace/parens 100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockwhitespace/tab 101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockwhitespace/todo 102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block""".split() 103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 1053ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochLINT_OUTPUT_PATTERN = re.compile(r'^.+[:(]\d+[:)]|^Done processing') 1063ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdochdef CppLintWorker(command): 1093ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch try: 1103ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch process = subprocess.Popen(command, stderr=subprocess.PIPE) 1113ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch process.wait() 1123ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch out_lines = "" 1133ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch error_count = -1 1143ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch while True: 1153ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch out_line = process.stderr.readline() 1163ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if out_line == '' and process.poll() != None: 1173ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch break 1183ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch m = LINT_OUTPUT_PATTERN.match(out_line) 1193ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if m: 1203ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch out_lines += out_line 1213ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch error_count += 1 1223ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch sys.stderr.write(out_lines) 1233ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return error_count 1243ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch except KeyboardInterrupt: 1253ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch process.kill() 1263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch except: 1273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch print('Error running cpplint.py. Please make sure you have depot_tools' + 1283ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch ' in your $PATH. Lint check skipped.') 1293ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch process.kill() 1303ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 1313ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 132d0582a6c46733687d045e4188a1bcd0123c758a1Steve Blockclass FileContentsCache(object): 133d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 134d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block def __init__(self, sums_file_name): 135d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block self.sums = {} 136d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block self.sums_file_name = sums_file_name 137d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 138d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block def Load(self): 139d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block try: 140d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block sums_file = None 141d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block try: 142d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block sums_file = open(self.sums_file_name, 'r') 143d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block self.sums = pickle.load(sums_file) 144d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block except IOError: 145d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block # File might not exist, this is OK. 146d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block pass 147d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block finally: 148d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if sums_file: 149d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block sums_file.close() 150d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 151d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block def Save(self): 152d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block try: 153d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block sums_file = open(self.sums_file_name, 'w') 154d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block pickle.dump(self.sums, sums_file) 155d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block finally: 156d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block sums_file.close() 157d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 158d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block def FilterUnchangedFiles(self, files): 159d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block changed_or_new = [] 160d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block for file in files: 161d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block try: 162d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block handle = open(file, "r") 163bb769b257e753aafcbd96767abb2abc645eaa20cBen Murdoch file_sum = md5er(handle.read()).digest() 164d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if not file in self.sums or self.sums[file] != file_sum: 165d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block changed_or_new.append(file) 166d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block self.sums[file] = file_sum 167d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block finally: 168d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block handle.close() 169d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block return changed_or_new 170d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 171d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block def RemoveFile(self, file): 172d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if file in self.sums: 173d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block self.sums.pop(file) 174d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 175d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass SourceFileProcessor(object): 177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block """ 178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Utility class that can run through a directory structure, find all relevant 179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block files and invoke a custom check on the files. 180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block """ 181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block def Run(self, path): 183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block all_files = [] 184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for file in self.GetPathsToSearch(): 185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block all_files += self.FindFilesIn(join(path, file)) 186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if not self.ProcessFiles(all_files, path): 187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return False 188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return True 189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block def IgnoreDir(self, name): 191d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block return name.startswith('.') or name == 'data' or name == 'sputniktests' 192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block def IgnoreFile(self, name): 194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return name.startswith('.') 195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block def FindFilesIn(self, path): 197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result = [] 198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for (root, dirs, files) in os.walk(path): 199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for ignored in [x for x in dirs if self.IgnoreDir(x)]: 200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block dirs.remove(ignored) 201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for file in files: 202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if not self.IgnoreFile(file) and self.IsRelevant(file): 203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result.append(join(root, file)) 204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return result 205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass CppLintProcessor(SourceFileProcessor): 208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block """ 209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block Lint files to check that they follow the google code style. 210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block """ 211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block def IsRelevant(self, name): 213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return name.endswith('.cc') or name.endswith('.h') 214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block def IgnoreDir(self, name): 216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return (super(CppLintProcessor, self).IgnoreDir(name) 217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block or (name == 'third_party')) 218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block IGNORE_LINT = ['flag-definitions.h'] 220d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block def IgnoreFile(self, name): 222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return (super(CppLintProcessor, self).IgnoreFile(name) 223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block or (name in CppLintProcessor.IGNORE_LINT)) 224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block def GetPathsToSearch(self): 2268a31eba00023874d4a1dcdc5f411cc4336776874Shimeng (Simon) Wang return ['src', 'preparser', 'include', 'samples', join('test', 'cctest')] 227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block def ProcessFiles(self, files, path): 229d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block good_files_cache = FileContentsCache('.cpplint-cache') 230d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block good_files_cache.Load() 231d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block files = good_files_cache.FilterUnchangedFiles(files) 232d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block if len(files) == 0: 233d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block print 'No changes in files detected. Skipping cpplint check.' 234d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block return True 235d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block filt = '-,' + ",".join(['+' + n for n in ENABLED_LINT_RULES]) 2373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch command = ['cpplint.py', '--filter', filt] 238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block local_cpplint = join(path, "tools", "cpplint.py") 239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if exists(local_cpplint): 2403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch command = ['python', local_cpplint, '--filter', filt] 241c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9Ben Murdoch 2423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch commands = join([command + [file] for file in files]) 2433ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch count = multiprocessing.cpu_count() 2443ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch pool = multiprocessing.Pool(count) 2453ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch try: 2463ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch results = pool.map_async(CppLintWorker, commands).get(999999) 2473ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch except KeyboardInterrupt: 2483ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch print "\nCaught KeyboardInterrupt, terminating workers." 2493ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch sys.exit(1) 2503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch 2513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch for i in range(len(files)): 2523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch if results[i] > 0: 2533ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch good_files_cache.RemoveFile(files[i]) 254d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block 2553ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch total_errors = sum(results) 2563ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch print "Total errors found: %d" % total_errors 257d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block good_files_cache.Save() 2583ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch return total_errors == 0 259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockCOPYRIGHT_HEADER_PATTERN = re.compile( 262e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke r'Copyright [\d-]*20[0-1][0-9] the V8 project authors. All rights reserved.') 263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass SourceProcessor(SourceFileProcessor): 265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block """ 266589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch Check that all files include a copyright notice and no trailing whitespaces. 267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block """ 268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block RELEVANT_EXTENSIONS = ['.js', '.cc', '.h', '.py', '.c', 'SConscript', 270589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 'SConstruct', '.status', '.gyp', '.gypi'] 271589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 272589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch # Overwriting the one in the parent class. 273589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch def FindFilesIn(self, path): 274589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch if os.path.exists(path+'/.git'): 275589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch output = subprocess.Popen('git ls-files --full-name', 276589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch stdout=PIPE, cwd=path, shell=True) 277589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch result = [] 278589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch for file in output.stdout.read().split(): 279589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch for dir_part in os.path.dirname(file).split(os.sep): 280589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch if self.IgnoreDir(dir_part): 281589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch break 282589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch else: 283589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch if self.IsRelevant(file) and not self.IgnoreFile(file): 284589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch result.append(join(path, file)) 285589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch if output.wait() == 0: 286589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch return result 287589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch return super(SourceProcessor, self).FindFilesIn(path) 288589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch 289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block def IsRelevant(self, name): 290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for ext in SourceProcessor.RELEVANT_EXTENSIONS: 291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if name.endswith(ext): 292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return True 293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return False 294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block def GetPathsToSearch(self): 296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return ['.'] 297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block def IgnoreDir(self, name): 299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return (super(SourceProcessor, self).IgnoreDir(name) 300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block or (name == 'third_party') 30169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch or (name == 'gyp') 30269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch or (name == 'out') 303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block or (name == 'obj')) 304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 30569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch IGNORE_COPYRIGHTS = ['cpplint.py', 30669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 'earley-boyer.js', 30769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 'raytrace.js', 30869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 'crypto.js', 30969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 'libraries.cc', 31069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 'libraries-empty.cc', 31169a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 'jsmin.py', 31269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch 'regexp-pcre.js'] 31369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch IGNORE_TABS = IGNORE_COPYRIGHTS + ['unicode-test.js', 'html-comments.js'] 314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block def ProcessContents(self, name, contents): 316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result = True 317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block base = basename(name) 318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if not base in SourceProcessor.IGNORE_TABS: 319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if '\t' in contents: 320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block print "%s contains tabs" % name 321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result = False 322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if not base in SourceProcessor.IGNORE_COPYRIGHTS: 323a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if not COPYRIGHT_HEADER_PATTERN.search(contents): 324a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block print "%s is missing a correct copyright header." % name 325a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result = False 326589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch ext = base.split('.').pop() 327589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch if ' \n' in contents or contents.endswith(' '): 328589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch line = 0 329589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch lines = [] 330589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch parts = contents.split(' \n') 331589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch if not contents.endswith(' '): 332589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch parts.pop() 333589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch for part in parts: 334589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch line += part.count('\n') + 1 335589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch lines.append(str(line)) 336589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch linenumbers = ', '.join(lines) 337589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch if len(lines) > 1: 338589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch print "%s has trailing whitespaces in lines %s." % (name, linenumbers) 339589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch else: 340589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch print "%s has trailing whitespaces in line %s." % (name, linenumbers) 341589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch result = False 342a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return result 343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block def ProcessFiles(self, files, path): 345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block success = True 346589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch violations = 0 347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block for file in files: 348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block try: 349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block handle = open(file) 350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block contents = handle.read() 351589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch if not self.ProcessContents(file, contents): 352589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch success = False 353589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch violations += 1 354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block finally: 355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block handle.close() 356589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch print "Total violating files: %s" % violations 357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return success 358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef GetOptions(): 361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result = optparse.OptionParser() 362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block result.add_option('--no-lint', help="Do not run cpplint", default=False, 363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block action="store_true") 364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return result 365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef Main(): 368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block workspace = abspath(join(dirname(sys.argv[0]), '..')) 369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block parser = GetOptions() 370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block (options, args) = parser.parse_args() 371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block success = True 372589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch print "Running C++ lint check..." 373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if not options.no_lint: 374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block success = CppLintProcessor().Run(workspace) and success 375589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch print "Running copyright header and trailing whitespaces check..." 376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block success = SourceProcessor().Run(workspace) and success 377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block if success: 378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return 0 379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block else: 380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block return 1 381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block 383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockif __name__ == '__main__': 384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block sys.exit(Main()) 385