#!/usr/bin/env python3 # Clang Format Helper # ------------------- # # Copyright (c) 2023 The Khronos Group Inc. # Copyright (c) 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # # This script retrieves the list of files to format from git and feeds it to # clang-format. It requires the following environment variable: # # CTS_CLANG_PATH=/path/to/clang-format # # which should point to clang-format from llvm 16.0.4 # # Usage: python3 run-clang-format.py # # -v: verbose output import argparse import multiprocessing import os import re import sys import time from common import getFilesModifiedSinceLastCommit, runCommandAsync, waitAsyncCommand def getClangFormat(): clang_format = os.environ.get('CTS_CLANG_FORMAT') if clang_format is not None: return clang_format print('CTS_CLANG_FORMAT is not defined. Set this environment variable to path to clang_format') if not sys.platform.startswith('linux'): sys.exit(1) print('Falling back to scripts/src_util/clang-format') clang_format = os.path.join(os.path.dirname(__file__), "clang-format") return clang_format def runClangFormat(files, thread_count, verbose): clang_format = getClangFormat() processes = [] total = len(files) so_far = 0 last_report_time = time.time() for file in files: so_far = so_far + 1 if verbose: print('Formatting {}'.format(file)) elif last_report_time + 1 < time.time(): print('\rFormatting {}/{}'.format(so_far, total), end = '') last_report_time = last_report_time + 1 # Make sure a maximum of thread_count processes are in flight if len(processes) > thread_count: waitAsyncCommand(*processes[0]) processes = processes[1:] command = [clang_format, file, '-i'] processes.append((runCommandAsync(command), command)) for process in processes: waitAsyncCommand(*process) print('\rFormatted {} '.format(total)) def runClangFormatOnModifiedFiles(verbose): files = getFilesModifiedSinceLastCommit() # Only format files that can be formatted by clang-format. pattern = (r'.*\.(cpp|hpp|c|h|m|mm|hh|inc|js|java|json)') files = [file for file in files if re.match('^%s$' % pattern, file, re.IGNORECASE)] files = [f for f in files if 'vulkancts/scripts/src' not in f.replace('\\', '/')] files = [f for f in files if not re.match(r'.*external/openglcts/modules/runner/.*Mustpass.*\.hpp', f.replace('\\', '/'))] thread_count = min(8, multiprocessing.cpu_count()) runClangFormat(files, thread_count, verbose) return True if __name__ == "__main__": parser = argparse.ArgumentParser( description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter ) parser.add_argument("-v", action="store_true", default=False, help="verbose") args = parser.parse_args() runClangFormatOnModifiedFiles(args.v)