• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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