190b0414b6c794be58f34813f84c2c06e6a15be91armvixl#!/usr/bin/env python2.7 290b0414b6c794be58f34813f84c2c06e6a15be91armvixl 30cc8b6ece4b3e757e11a906a81ece292437713abarmvixl# Copyright 2015, ARM Limited 490b0414b6c794be58f34813f84c2c06e6a15be91armvixl# All rights reserved. 590b0414b6c794be58f34813f84c2c06e6a15be91armvixl# 690b0414b6c794be58f34813f84c2c06e6a15be91armvixl# Redistribution and use in source and binary forms, with or without 790b0414b6c794be58f34813f84c2c06e6a15be91armvixl# modification, are permitted provided that the following conditions are met: 890b0414b6c794be58f34813f84c2c06e6a15be91armvixl# 990b0414b6c794be58f34813f84c2c06e6a15be91armvixl# * Redistributions of source code must retain the above copyright notice, 1090b0414b6c794be58f34813f84c2c06e6a15be91armvixl# this list of conditions and the following disclaimer. 1190b0414b6c794be58f34813f84c2c06e6a15be91armvixl# * Redistributions in binary form must reproduce the above copyright notice, 1290b0414b6c794be58f34813f84c2c06e6a15be91armvixl# this list of conditions and the following disclaimer in the documentation 1390b0414b6c794be58f34813f84c2c06e6a15be91armvixl# and/or other materials provided with the distribution. 1490b0414b6c794be58f34813f84c2c06e6a15be91armvixl# * Neither the name of ARM Limited nor the names of its contributors may be 1590b0414b6c794be58f34813f84c2c06e6a15be91armvixl# used to endorse or promote products derived from this software without 1690b0414b6c794be58f34813f84c2c06e6a15be91armvixl# specific prior written permission. 1790b0414b6c794be58f34813f84c2c06e6a15be91armvixl# 1890b0414b6c794be58f34813f84c2c06e6a15be91armvixl# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND 1990b0414b6c794be58f34813f84c2c06e6a15be91armvixl# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 2090b0414b6c794be58f34813f84c2c06e6a15be91armvixl# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2190b0414b6c794be58f34813f84c2c06e6a15be91armvixl# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 2290b0414b6c794be58f34813f84c2c06e6a15be91armvixl# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2390b0414b6c794be58f34813f84c2c06e6a15be91armvixl# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2490b0414b6c794be58f34813f84c2c06e6a15be91armvixl# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 2590b0414b6c794be58f34813f84c2c06e6a15be91armvixl# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2690b0414b6c794be58f34813f84c2c06e6a15be91armvixl# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2790b0414b6c794be58f34813f84c2c06e6a15be91armvixl# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2890b0414b6c794be58f34813f84c2c06e6a15be91armvixl 2990b0414b6c794be58f34813f84c2c06e6a15be91armvixlimport argparse 3090b0414b6c794be58f34813f84c2c06e6a15be91armvixlimport multiprocessing 3190b0414b6c794be58f34813f84c2c06e6a15be91armvixlimport re 3290b0414b6c794be58f34813f84c2c06e6a15be91armvixlimport subprocess 3390b0414b6c794be58f34813f84c2c06e6a15be91armvixlimport sys 3490b0414b6c794be58f34813f84c2c06e6a15be91armvixl 3590b0414b6c794be58f34813f84c2c06e6a15be91armvixlimport git 3690b0414b6c794be58f34813f84c2c06e6a15be91armvixlimport printer 3790b0414b6c794be58f34813f84c2c06e6a15be91armvixlimport util 3890b0414b6c794be58f34813f84c2c06e6a15be91armvixl 3990b0414b6c794be58f34813f84c2c06e6a15be91armvixl 4090b0414b6c794be58f34813f84c2c06e6a15be91armvixl# Google's cpplint.py from depot_tools is the linter used here. 4190b0414b6c794be58f34813f84c2c06e6a15be91armvixl# These are positive rules, added to the set of rules that the linter checks. 4290b0414b6c794be58f34813f84c2c06e6a15be91armvixlCPP_LINTER_RULES = ''' 4390b0414b6c794be58f34813f84c2c06e6a15be91armvixlbuild/class 4490b0414b6c794be58f34813f84c2c06e6a15be91armvixlbuild/deprecated 4590b0414b6c794be58f34813f84c2c06e6a15be91armvixlbuild/endif_comment 4690b0414b6c794be58f34813f84c2c06e6a15be91armvixlbuild/forward_decl 4790b0414b6c794be58f34813f84c2c06e6a15be91armvixlbuild/include_order 4890b0414b6c794be58f34813f84c2c06e6a15be91armvixlbuild/printf_format 4990b0414b6c794be58f34813f84c2c06e6a15be91armvixlbuild/storage_class 5090b0414b6c794be58f34813f84c2c06e6a15be91armvixllegal/copyright 5190b0414b6c794be58f34813f84c2c06e6a15be91armvixlreadability/boost 5290b0414b6c794be58f34813f84c2c06e6a15be91armvixlreadability/braces 5390b0414b6c794be58f34813f84c2c06e6a15be91armvixlreadability/casting 5490b0414b6c794be58f34813f84c2c06e6a15be91armvixlreadability/constructors 5590b0414b6c794be58f34813f84c2c06e6a15be91armvixlreadability/fn_size 5690b0414b6c794be58f34813f84c2c06e6a15be91armvixlreadability/function 5790b0414b6c794be58f34813f84c2c06e6a15be91armvixlreadability/multiline_comment 5890b0414b6c794be58f34813f84c2c06e6a15be91armvixlreadability/multiline_string 5990b0414b6c794be58f34813f84c2c06e6a15be91armvixlreadability/streams 6090b0414b6c794be58f34813f84c2c06e6a15be91armvixlreadability/utf8 6190b0414b6c794be58f34813f84c2c06e6a15be91armvixlruntime/arrays 6290b0414b6c794be58f34813f84c2c06e6a15be91armvixlruntime/casting 6390b0414b6c794be58f34813f84c2c06e6a15be91armvixlruntime/deprecated_fn 6490b0414b6c794be58f34813f84c2c06e6a15be91armvixlruntime/explicit 6590b0414b6c794be58f34813f84c2c06e6a15be91armvixlruntime/int 6690b0414b6c794be58f34813f84c2c06e6a15be91armvixlruntime/memset 6790b0414b6c794be58f34813f84c2c06e6a15be91armvixlruntime/mutex 6890b0414b6c794be58f34813f84c2c06e6a15be91armvixlruntime/nonconf 6990b0414b6c794be58f34813f84c2c06e6a15be91armvixlruntime/printf 7090b0414b6c794be58f34813f84c2c06e6a15be91armvixlruntime/printf_format 7190b0414b6c794be58f34813f84c2c06e6a15be91armvixlruntime/references 7290b0414b6c794be58f34813f84c2c06e6a15be91armvixlruntime/rtti 7390b0414b6c794be58f34813f84c2c06e6a15be91armvixlruntime/sizeof 7490b0414b6c794be58f34813f84c2c06e6a15be91armvixlruntime/string 7590b0414b6c794be58f34813f84c2c06e6a15be91armvixlruntime/virtual 7690b0414b6c794be58f34813f84c2c06e6a15be91armvixlruntime/vlog 7790b0414b6c794be58f34813f84c2c06e6a15be91armvixlwhitespace/blank_line 7890b0414b6c794be58f34813f84c2c06e6a15be91armvixlwhitespace/braces 7990b0414b6c794be58f34813f84c2c06e6a15be91armvixlwhitespace/comma 8090b0414b6c794be58f34813f84c2c06e6a15be91armvixlwhitespace/comments 8190b0414b6c794be58f34813f84c2c06e6a15be91armvixlwhitespace/end_of_line 8290b0414b6c794be58f34813f84c2c06e6a15be91armvixlwhitespace/ending_newline 8390b0414b6c794be58f34813f84c2c06e6a15be91armvixlwhitespace/indent 8490b0414b6c794be58f34813f84c2c06e6a15be91armvixlwhitespace/labels 8590b0414b6c794be58f34813f84c2c06e6a15be91armvixlwhitespace/line_length 8690b0414b6c794be58f34813f84c2c06e6a15be91armvixlwhitespace/newline 8790b0414b6c794be58f34813f84c2c06e6a15be91armvixlwhitespace/operators 8890b0414b6c794be58f34813f84c2c06e6a15be91armvixlwhitespace/parens 8990b0414b6c794be58f34813f84c2c06e6a15be91armvixlwhitespace/tab 9090b0414b6c794be58f34813f84c2c06e6a15be91armvixlwhitespace/todo 9190b0414b6c794be58f34813f84c2c06e6a15be91armvixl'''.split() 9290b0414b6c794be58f34813f84c2c06e6a15be91armvixl 9390b0414b6c794be58f34813f84c2c06e6a15be91armvixl 9490b0414b6c794be58f34813f84c2c06e6a15be91armvixl 9590b0414b6c794be58f34813f84c2c06e6a15be91armvixldef BuildOptions(): 9690b0414b6c794be58f34813f84c2c06e6a15be91armvixl result = argparse.ArgumentParser( 9790b0414b6c794be58f34813f84c2c06e6a15be91armvixl description = 9890b0414b6c794be58f34813f84c2c06e6a15be91armvixl '''This tool lints the C++ files tracked by the git repository, and 9990b0414b6c794be58f34813f84c2c06e6a15be91armvixl produces a summary of the errors found.''', 10090b0414b6c794be58f34813f84c2c06e6a15be91armvixl # Print default values. 10190b0414b6c794be58f34813f84c2c06e6a15be91armvixl formatter_class=argparse.ArgumentDefaultsHelpFormatter) 10290b0414b6c794be58f34813f84c2c06e6a15be91armvixl result.add_argument('--jobs', '-j', metavar='N', type=int, nargs='?', 10390b0414b6c794be58f34813f84c2c06e6a15be91armvixl default=1, const=multiprocessing.cpu_count(), 10490b0414b6c794be58f34813f84c2c06e6a15be91armvixl help='''Runs the tests using N jobs. If the option is set 10590b0414b6c794be58f34813f84c2c06e6a15be91armvixl but no value is provided, the script will use as many jobs 10690b0414b6c794be58f34813f84c2c06e6a15be91armvixl as it thinks useful.''') 10790b0414b6c794be58f34813f84c2c06e6a15be91armvixl result.add_argument('--verbose', action='store_true', 10890b0414b6c794be58f34813f84c2c06e6a15be91armvixl help='Print verbose output.') 10990b0414b6c794be58f34813f84c2c06e6a15be91armvixl return result.parse_args() 11090b0414b6c794be58f34813f84c2c06e6a15be91armvixl 11190b0414b6c794be58f34813f84c2c06e6a15be91armvixl 11290b0414b6c794be58f34813f84c2c06e6a15be91armvixl 11390b0414b6c794be58f34813f84c2c06e6a15be91armvixl__lint_results_lock__ = multiprocessing.Lock() 11490b0414b6c794be58f34813f84c2c06e6a15be91armvixl 11590b0414b6c794be58f34813f84c2c06e6a15be91armvixl# Returns the number of errors in the file linted. 11690b0414b6c794be58f34813f84c2c06e6a15be91armvixldef Lint(filename, lint_options, progress_prefix = '', verbose = False): 11790b0414b6c794be58f34813f84c2c06e6a15be91armvixl command = ['cpplint.py', lint_options, filename] 11890b0414b6c794be58f34813f84c2c06e6a15be91armvixl process = subprocess.Popen(command, 11990b0414b6c794be58f34813f84c2c06e6a15be91armvixl stdout=subprocess.PIPE, 12090b0414b6c794be58f34813f84c2c06e6a15be91armvixl stderr=subprocess.PIPE) 12190b0414b6c794be58f34813f84c2c06e6a15be91armvixl 12290b0414b6c794be58f34813f84c2c06e6a15be91armvixl # Use a lock to avoid mixing the output for different files. 12390b0414b6c794be58f34813f84c2c06e6a15be91armvixl with __lint_results_lock__: 12490b0414b6c794be58f34813f84c2c06e6a15be91armvixl # Process the output as the process is running, until it exits. 12590b0414b6c794be58f34813f84c2c06e6a15be91armvixl LINT_ERROR_LINE_REGEXP = re.compile('\[[1-5]\]$') 12690b0414b6c794be58f34813f84c2c06e6a15be91armvixl LINT_DONE_PROC_LINE_REGEXP = re.compile('Done processing') 12790b0414b6c794be58f34813f84c2c06e6a15be91armvixl LINT_STATUS_LINE_REGEXP = re.compile('Total errors found') 12890b0414b6c794be58f34813f84c2c06e6a15be91armvixl while True: 12990b0414b6c794be58f34813f84c2c06e6a15be91armvixl retcode = process.poll() 13090b0414b6c794be58f34813f84c2c06e6a15be91armvixl while True: 13190b0414b6c794be58f34813f84c2c06e6a15be91armvixl line = process.stderr.readline() 13290b0414b6c794be58f34813f84c2c06e6a15be91armvixl if line == '': break 13390b0414b6c794be58f34813f84c2c06e6a15be91armvixl output_line = progress_prefix + line.rstrip('\r\n') 13490b0414b6c794be58f34813f84c2c06e6a15be91armvixl 13590b0414b6c794be58f34813f84c2c06e6a15be91armvixl if LINT_ERROR_LINE_REGEXP.search(line): 13690b0414b6c794be58f34813f84c2c06e6a15be91armvixl printer.PrintOverwritableLine(output_line, verbose = verbose) 13790b0414b6c794be58f34813f84c2c06e6a15be91armvixl printer.EnsureNewLine() 13890b0414b6c794be58f34813f84c2c06e6a15be91armvixl elif LINT_DONE_PROC_LINE_REGEXP.search(line): 13990b0414b6c794be58f34813f84c2c06e6a15be91armvixl printer.PrintOverwritableLine(output_line, verbose = verbose) 14090b0414b6c794be58f34813f84c2c06e6a15be91armvixl elif LINT_STATUS_LINE_REGEXP.search(line): 14190b0414b6c794be58f34813f84c2c06e6a15be91armvixl status_line = line 14290b0414b6c794be58f34813f84c2c06e6a15be91armvixl 14390b0414b6c794be58f34813f84c2c06e6a15be91armvixl if retcode != None: break; 14490b0414b6c794be58f34813f84c2c06e6a15be91armvixl 14590b0414b6c794be58f34813f84c2c06e6a15be91armvixl if retcode == 0: 14690b0414b6c794be58f34813f84c2c06e6a15be91armvixl return 0 14790b0414b6c794be58f34813f84c2c06e6a15be91armvixl 14890b0414b6c794be58f34813f84c2c06e6a15be91armvixl # Return the number of errors in this file. 14990b0414b6c794be58f34813f84c2c06e6a15be91armvixl res = re.search('\d+$', status_line) 15090b0414b6c794be58f34813f84c2c06e6a15be91armvixl n_errors_str = res.string[res.start():res.end()] 15190b0414b6c794be58f34813f84c2c06e6a15be91armvixl n_errors = int(n_errors_str) 15290b0414b6c794be58f34813f84c2c06e6a15be91armvixl status_line = \ 15390b0414b6c794be58f34813f84c2c06e6a15be91armvixl progress_prefix + 'Total errors found in %s : %d' % (filename, n_errors) 15490b0414b6c794be58f34813f84c2c06e6a15be91armvixl printer.PrintOverwritableLine(status_line, verbose = verbose) 15590b0414b6c794be58f34813f84c2c06e6a15be91armvixl printer.EnsureNewLine() 15690b0414b6c794be58f34813f84c2c06e6a15be91armvixl return n_errors 15790b0414b6c794be58f34813f84c2c06e6a15be91armvixl 15890b0414b6c794be58f34813f84c2c06e6a15be91armvixl 15990b0414b6c794be58f34813f84c2c06e6a15be91armvixl# The multiprocessing map_async function does not allow passing multiple 16090b0414b6c794be58f34813f84c2c06e6a15be91armvixl# arguments directly, so use a wrapper. 16190b0414b6c794be58f34813f84c2c06e6a15be91armvixldef LintWrapper(args): 16290b0414b6c794be58f34813f84c2c06e6a15be91armvixl return Lint(*args) 16390b0414b6c794be58f34813f84c2c06e6a15be91armvixl 16490b0414b6c794be58f34813f84c2c06e6a15be91armvixl 16590b0414b6c794be58f34813f84c2c06e6a15be91armvixl# Returns the total number of errors found in the files linted. 16690b0414b6c794be58f34813f84c2c06e6a15be91armvixldef LintFiles(files, lint_args = CPP_LINTER_RULES, jobs = 1, verbose = False, 16790b0414b6c794be58f34813f84c2c06e6a15be91armvixl progress_prefix = ''): 16890b0414b6c794be58f34813f84c2c06e6a15be91armvixl lint_options = '--filter=-,+' + ',+'.join(lint_args) 16990b0414b6c794be58f34813f84c2c06e6a15be91armvixl pool = multiprocessing.Pool(jobs) 17090b0414b6c794be58f34813f84c2c06e6a15be91armvixl # The '.get(9999999)' is workaround to allow killing the test script with 17190b0414b6c794be58f34813f84c2c06e6a15be91armvixl # ctrl+C from the shell. This bug is documented at 17290b0414b6c794be58f34813f84c2c06e6a15be91armvixl # http://bugs.python.org/issue8296. 17390b0414b6c794be58f34813f84c2c06e6a15be91armvixl tasks = [(f, lint_options, progress_prefix, verbose) for f in files] 17490b0414b6c794be58f34813f84c2c06e6a15be91armvixl results = pool.map_async(LintWrapper, tasks).get(9999999) 17590b0414b6c794be58f34813f84c2c06e6a15be91armvixl n_errors = sum(results) 17690b0414b6c794be58f34813f84c2c06e6a15be91armvixl 17790b0414b6c794be58f34813f84c2c06e6a15be91armvixl printer.PrintOverwritableLine( 17890b0414b6c794be58f34813f84c2c06e6a15be91armvixl progress_prefix + 'Total errors found: %d' % n_errors) 17990b0414b6c794be58f34813f84c2c06e6a15be91armvixl printer.EnsureNewLine() 18090b0414b6c794be58f34813f84c2c06e6a15be91armvixl return n_errors 18190b0414b6c794be58f34813f84c2c06e6a15be91armvixl 18290b0414b6c794be58f34813f84c2c06e6a15be91armvixl 18390b0414b6c794be58f34813f84c2c06e6a15be91armvixldef IsCppLintAvailable(): 18490b0414b6c794be58f34813f84c2c06e6a15be91armvixl retcode, unused_output = util.getstatusoutput('which cpplint.py') 18590b0414b6c794be58f34813f84c2c06e6a15be91armvixl return retcode == 0 18690b0414b6c794be58f34813f84c2c06e6a15be91armvixl 18790b0414b6c794be58f34813f84c2c06e6a15be91armvixl 18890b0414b6c794be58f34813f84c2c06e6a15be91armvixlCPP_EXT_REGEXP = re.compile('\.(cc|h)$') 1890cc8b6ece4b3e757e11a906a81ece292437713abarmvixlSIM_TRACES_REGEXP = re.compile('trace-a64\.h$') 19090b0414b6c794be58f34813f84c2c06e6a15be91armvixldef is_linter_input(filename): 19190b0414b6c794be58f34813f84c2c06e6a15be91armvixl # Don't lint the simulator traces file; it takes a very long time to check 19290b0414b6c794be58f34813f84c2c06e6a15be91armvixl # and it's (mostly) generated automatically anyway. 19390b0414b6c794be58f34813f84c2c06e6a15be91armvixl if SIM_TRACES_REGEXP.search(filename): return False 19490b0414b6c794be58f34813f84c2c06e6a15be91armvixl # Otherwise, lint all C++ files. 19590b0414b6c794be58f34813f84c2c06e6a15be91armvixl return CPP_EXT_REGEXP.search(filename) != None 19690b0414b6c794be58f34813f84c2c06e6a15be91armvixldefault_tracked_files = git.get_tracked_files().split() 19790b0414b6c794be58f34813f84c2c06e6a15be91armvixldefault_tracked_files = filter(is_linter_input, default_tracked_files) 19890b0414b6c794be58f34813f84c2c06e6a15be91armvixl 19990b0414b6c794be58f34813f84c2c06e6a15be91armvixlif __name__ == '__main__': 20090b0414b6c794be58f34813f84c2c06e6a15be91armvixl # Parse the arguments. 20190b0414b6c794be58f34813f84c2c06e6a15be91armvixl args = BuildOptions() 20290b0414b6c794be58f34813f84c2c06e6a15be91armvixl 20390b0414b6c794be58f34813f84c2c06e6a15be91armvixl retcode = LintFiles(default_tracked_files, 20490b0414b6c794be58f34813f84c2c06e6a15be91armvixl jobs = args.jobs, verbose = args.verbose) 20590b0414b6c794be58f34813f84c2c06e6a15be91armvixl sys.exit(retcode) 206