1#!/usr/bin/env python3 2# -- coding: utf-8 -- 3# Copyright (c) 2022-2024 Huawei Device Co., Ltd. 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16import argparse 17import os 18import multiprocessing 19import re 20import sys 21import subprocess 22import time 23 24 25CLANG_FORMAT = "clang-format-14" 26 27 28def get_args(): 29 parser = argparse.ArgumentParser( 30 description="Runner for clang-format for panda project.") 31 parser.add_argument( 32 'panda_dir', help='panda sources directory.') 33 parser.add_argument( 34 '--reformat', action="store_true", help='reformat files.') 35 parser.add_argument( 36 '--proc-count', type=int, action='store', dest='proc_count', 37 required=False, default="-1", 38 help='Paralell process count of clang-format') 39 return parser.parse_args() 40 41 42def run_clang_format(src_path, panda_dir, reformat, msg): 43 check_cmd = [str(os.path.join(panda_dir, 'scripts', 'code_style', 44 'run_code_style_tools.sh'))] 45 reformat_cmd = [CLANG_FORMAT, '-i'] 46 cmd = reformat_cmd if reformat else check_cmd 47 cmd += [src_path] 48 49 print(msg) 50 51 try: 52 subprocess.check_output(cmd, stderr=subprocess.STDOUT) 53 except subprocess.CalledProcessError as e: 54 # Skip error for some invalid release configurations. 55 if not e.stdout: 56 print("Note: missed output for ", src_path) 57 return True 58 59 print('Failed: ', ' '.join(cmd)) 60 print(e.stdout.decode()) 61 62 if e.stderr: 63 print(e.stderr.decode()) 64 65 return False 66 67 return True 68 69 70def get_proc_count(cmd_ard : int) -> int: 71 if cmd_ard > 0: 72 return cmd_ard 73 74 min_proc_str = os.getenv('NPROC_PER_JOB') 75 if min_proc_str: 76 return int(min_proc_str) 77 78 return multiprocessing.cpu_count() 79 80 81def check_file_list(file_list : list, panda_dir : str, reformat : bool, proc_count : int): 82 pool = multiprocessing.Pool(proc_count) 83 jobs = [] 84 main_ret_val = True 85 total_count = str(len(file_list)) 86 idx = 0 87 for src in file_list: 88 idx += 1 89 msg = "[%s/%s] Running clang-format: %s" % (str(idx), total_count, src) 90 proc = pool.apply_async(func=run_clang_format, args=( 91 src, panda_dir, reformat, msg)) 92 jobs.append(proc) 93 94 # Wait for jobs to complete before exiting 95 while(not all([p.ready() for p in jobs])): 96 time.sleep(5) 97 98 for job in jobs: 99 if not job.get(): 100 main_ret_val = False 101 break 102 103 # Safely terminate the pool 104 pool.close() 105 pool.join() 106 107 return main_ret_val 108 109 110def get_file_list(panda_dir): 111 src_exts = (".c", '.cc', ".cp", ".cxx", ".cpp", ".CPP", ".c++", ".C", ".h", 112 ".hh", ".H", ".hp", ".hxx", ".hpp", ".HPP", ".h++", ".tcc", ".inc") 113 skip_dirs = ["third_party", "artifacts", "build.*"] 114 file_list = [] 115 for dirpath, dirnames, filenames in os.walk(panda_dir, followlinks=True): 116 dirnames[:] = [d for d in dirnames if not re.match(f"({')|('.join(skip_dirs)})", d)] 117 for fname in filenames: 118 if (fname.endswith(src_exts)): 119 full_path = os.path.join(panda_dir, dirpath, fname) 120 full_path = str(os.path.realpath(full_path)) 121 file_list.append(full_path) 122 123 return file_list 124 125 126if __name__ == "__main__": 127 args = get_args() 128 files_list = [] 129 130 files_list = get_file_list(args.panda_dir) 131 132 if not files_list: 133 sys.exit( 134 "Can't be prepaired source list. Please check panda_dir variable: " + args.panda_dir) 135 136 process_count = get_proc_count(args.proc_count) 137 print('clang-format proc_count: ' + str(process_count)) 138 139 if not check_file_list(files_list, args.panda_dir, args.reformat, process_count): 140 sys.exit("Failed: clang-format get errors") 141 142 print("Clang-format was passed successfully!") 143