VIXL Release 1.13
Refer to the README.md and LICENCE files for details.
Change-Id: I922914f4e7da7cb939a8054cded11feb9ea51a86
diff --git a/tools/clang_format.py b/tools/clang_format.py
new file mode 100755
index 0000000..50dc0eb
--- /dev/null
+++ b/tools/clang_format.py
@@ -0,0 +1,193 @@
+#!/usr/bin/env python2.7
+
+# Copyright 2016, ARM Limited
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of ARM Limited nor the names of its contributors may be
+# used to endorse or promote products derived from this software without
+# specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import argparse
+import fnmatch
+import multiprocessing
+import os
+import signal
+import subprocess
+import sys
+import tempfile
+
+import config
+import git
+import printer
+import util
+
+
+is_output_redirected = not sys.stdout.isatty()
+
+# Catch SIGINT to gracefully exit when ctrl+C is pressed.
+def sigint_handler(signal, frame):
+ sys.exit(1)
+signal.signal(signal.SIGINT, sigint_handler)
+
+def BuildOptions():
+ parser = argparse.ArgumentParser(
+ description = '''This tool runs `clang-format` on C++ files.
+ If no files are provided on the command-line, all C++ source files in `src`,
+ `sample`, and `benchmarks` are processed.
+ When available, `colordiff` is automatically used to clour the output.''',
+ # Print default values.
+ formatter_class = argparse.ArgumentDefaultsHelpFormatter)
+ parser.add_argument('files', nargs = '*')
+ parser.add_argument('--in-place', '-i',
+ action = 'store_true', default = False,
+ help = 'Edit files in place.')
+ parser.add_argument('--jobs', '-j', metavar = 'N', type = int, nargs = '?',
+ default = multiprocessing.cpu_count(),
+ const = multiprocessing.cpu_count(),
+ help = '''Runs the tests using N jobs. If the option is set
+ but no value is provided, the script will use as many jobs
+ as it thinks useful.''')
+ return parser.parse_args()
+
+
+# Returns 0 if the file is correctly formatted, or 1 otherwise.
+def ClangFormat(filename, in_place = False, progress_prefix = ''):
+ rc = 0
+ printer.PrintOverwritableLine('Processing %s' % filename,
+ type = printer.LINE_TYPE_LINTER)
+
+ cmd_format = ['clang-format-3.6', filename]
+ temp_file, temp_file_name = tempfile.mkstemp(prefix = 'clang_format_')
+ cmd_format_string = '$ ' + ' '.join(cmd_format) + ' > %s' % temp_file_name
+ p_format = subprocess.Popen(cmd_format,
+ stdout = temp_file, stderr = subprocess.STDOUT)
+
+ rc += p_format.wait()
+
+ cmd_diff = ['diff', '--unified', filename, temp_file_name]
+ cmd_diff_string = '$ ' + ' '.join(cmd_diff)
+ p_diff = subprocess.Popen(cmd_diff,
+ stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
+
+ if util.IsCommandAvailable('colordiff') and not is_output_redirected:
+ p_colordiff = subprocess.Popen(
+ ['colordiff', '--unified'],
+ stdin = p_diff.stdout,
+ stdout = subprocess.PIPE, stderr = subprocess.STDOUT)
+ out, unused = p_colordiff.communicate()
+ else:
+ out, unused = p_diff.communicate()
+
+ rc += p_diff.wait()
+
+ if in_place:
+ cmd_format = ['clang-format-3.6', '-i', filename]
+ p_format = subprocess.Popen(cmd_format,
+ stdout=temp_file, stderr=subprocess.STDOUT)
+
+ if rc != 0:
+ printer.Print('Incorrectly formatted file: ' + filename + '\n' + \
+ cmd_format_string + '\n' + \
+ cmd_diff_string + '\n' + \
+ out)
+
+ return 0 if rc == 0 else 1
+
+
+# The multiprocessing map_async function does not allow passing multiple
+# arguments directly, so use a wrapper.
+def ClangFormatWrapper(args):
+ # Run under a try-catch to avoid flooding the output when the script is
+ # interrupted from the keyboard with ctrl+C.
+ try:
+ return ClangFormat(*args)
+ except:
+ sys.exit(1)
+
+
+# Returns the total number of files incorrectly formatted.
+def ClangFormatFiles(files, in_place = False, jobs = 1, progress_prefix = ''):
+ if not util.IsCommandAvailable('clang-format-3.6'):
+ print(
+ printer.COLOUR_RED + \
+ ("`clang-format-3.6` not found. Please ensure it is installed "
+ "and in your PATH.") + \
+ printer.NO_COLOUR)
+ return -1
+
+ pool = multiprocessing.Pool(jobs)
+ # The '.get(9999999)' is workaround to allow killing the test script with
+ # ctrl+C from the shell. This bug is documented at
+ # http://bugs.python.org/issue8296.
+ tasks = [(f, in_place, progress_prefix) for f in files]
+ # Run under a try-catch to avoid flooding the output when the script is
+ # interrupted from the keyboard with ctrl+C.
+ try:
+ results = pool.map_async(ClangFormatWrapper, tasks).get(9999999)
+ pool.close()
+ pool.join()
+ except KeyboardInterrupt:
+ pool.terminate()
+ sys.exit(1)
+ rc = sum(results)
+
+ printer.PrintOverwritableLine(
+ progress_prefix + '%d files are incorrectly formatted.' % rc,
+ type = printer.LINE_TYPE_LINTER)
+ printer.EnsureNewLine()
+ return rc
+
+
+def Find(path, filters = ['*']):
+ files_found = []
+
+ def NameMatchesAnyFilter(name, ff):
+ for f in ff:
+ if fnmatch.fnmatch(name, f):
+ return True
+ return False
+
+ for root, dirs, files in os.walk(path):
+ files_found += [os.path.relpath(os.path.join(root, fn))
+ for fn in files if NameMatchesAnyFilter(fn, filters)]
+ return files_found
+
+
+def GetCppSourceFilesToFormat():
+ sources = []
+ source_dirs = [config.dir_benchmarks,
+ config.dir_examples,
+ config.dir_src_vixl ]
+ for directory in source_dirs:
+ sources += Find(directory, ['*.h', '*.cc'])
+ return sources
+
+
+if __name__ == '__main__':
+ # Parse the arguments.
+ args = BuildOptions()
+ files = args.files
+ if not files:
+ files = GetCppSourceFilesToFormat()
+
+ rc = ClangFormatFiles(files, in_place = args.in_place, jobs = args.jobs)
+ sys.exit(rc)