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