forked from CNES/pangeo-pyinterp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrun-clang-tidy.py
149 lines (132 loc) · 5.27 KB
/
run-clang-tidy.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# Copyright (c) 2022 CNES
#
# All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
import argparse
import concurrent.futures
import multiprocessing
import os
import platform
import re
import subprocess
import sys
import sysconfig
def directory_type(value):
"""The option must define a path to a directory"""
path = os.path.abspath(value)
if not os.path.isdir(path):
raise argparse.ArgumentTypeError('%r is not a directory' % value)
return path
def usage():
"""Parse arguments"""
parser = argparse.ArgumentParser(description="Parallel clang-tidy runner")
parser.add_argument('--include',
nargs="+",
type=directory_type,
help='Add directory to include search path')
parser.add_argument('--jobs',
type=int,
default=multiprocessing.cpu_count(),
help='number of tidy instances to be run in parallel.')
parser.add_argument('--fix',
action="store_true",
help="Apply suggested fixes. Without -fix-errors "
"clang-tidy will bail out if any compilation "
"errors were found")
parser.add_argument("--log",
type=argparse.FileType("w"),
help="path to the file containing the execution log.")
parser.add_argument("--pattern",
help="Pattern to select files to be taken into "
"account in the processing.")
parser.add_argument(
"--clang-tidy",
help='path to the "clang-tidy" program to be executed.',
default="clang-tidy")
return parser.parse_args()
def run(program, fix, path, options=""):
"""Launch clang-tidy"""
args = [
program, '-checks=*,-llvm-header-guard,-fuchsia-*,-android-*,'
'-*-magic-numbers,-google-runtime-references,'
'-altera-*,-bugprone-*,'
'-cppcoreguidelines-init-variables,'
'-cppcoreguidelines-owning-memory,'
'-cppcoreguidelines-pro-bounds-array-to-pointer-decay,'
'-cppcoreguidelines-pro-bounds-constant-array-index,'
'-cppcoreguidelines-pro-bounds-pointer-arithmetic,'
'-cppcoreguidelines-pro-type-cstyle-cast,'
'-cppcoreguidelines-pro-type-reinterpret-cast,'
'-cppcoreguidelines-pro-type-vararg,'
'-llvmlibc-*,'
'-hicpp-*,'
'-*-non-private-member-variables-in-classes', '-format-style=Google',
path, '--', options
]
if fix:
args.insert(2, "-fix")
process = subprocess.Popen(" ".join(args),
shell=True,
bufsize=4096,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
stdout, _ = process.communicate()
stdout = stdout.decode('utf8')
if process.returncode != 0:
raise RuntimeError(stdout)
return " ".join(args) + "\n" + stdout
def main():
"""Main function"""
args = usage()
target = []
# Root of project
root = os.path.normpath(
os.path.join(os.path.dirname(os.path.basename(__file__))))
# Directories to include in search path
includes = [] if args.include is None else args.include
if platform.system() == 'Darwin':
sysroot = (" -isysroot "
"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk")
else:
sysroot = ""
includes.insert(0, sysconfig.get_config_var('INCLUDEPY'))
includes.insert(0, f"{sys.prefix}/include/eigen3")
includes.insert(0, f"{sys.prefix}/include")
includes.insert(0, f"{root}/third_party/pybind11/include")
includes.insert(0, f"{root}/src/pyinterp/core/include")
pattern = re.compile(args.pattern).search if args.pattern else None
# Enumerates files to be processed
for dirname in [f"{root}/src/pyinterp/core"]:
for root, dirs, files in os.walk(dirname):
if 'tests' in dirs:
dirs.remove('tests')
for item in files:
path = os.path.join(root, item)
if pattern is not None and pattern(path) is None:
continue
if item.endswith(".cpp") or item.endswith(".hpp"):
target.append(path)
# Compiler options
options = "-std=c++17 " + " ".join(
(f"-I{item}" for item in includes)) + sysroot
# Stream used to write in the logbook
stream = sys.stderr if args.log is None else args.log
# Finally, we run all code checks
with concurrent.futures.ThreadPoolExecutor(
max_workers=args.jobs) as executor:
future_to_lint = {
executor.submit(run, args.clang_tidy, args.fix, path, options):
path
for path in target
}
for future in concurrent.futures.as_completed(future_to_lint):
path = future_to_lint[future]
print(path)
try:
stream.write(future.result() + "\n")
stream.flush()
except Exception as exc:
raise RuntimeError('%r generated an exception: %s' %
(path, exc))
if __name__ == "__main__":
main()