-
Notifications
You must be signed in to change notification settings - Fork 1
/
run_clang_format.py
150 lines (112 loc) · 4.46 KB
/
run_clang_format.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
150
#!/usr/bin/env python
# pylint: disable=C0111
"""
Runs clang format over all cpp files
"""
from __future__ import print_function
import argparse
import fnmatch
import os
import multiprocessing
import queue
import subprocess
import sys
import threading
def glob_files(args):
files = []
extensions = args.extensions.split(',')
for directory in args.directories:
for root, _, filenames in os.walk(directory):
for ext in extensions:
for filename in fnmatch.filter(filenames, '*.' + ext):
files.append(os.path.join(root, filename))
return files
def parse_args(argv=None):
if argv is None:
argv = sys.argv
parser = argparse.ArgumentParser(
description='Runs clang-format over all files in given directories.'
' Requires clang-format in PATH.')
parser.add_argument('--clang-format-binary', metavar='PATH',
default='clang-format',
help='path to clang-format binary')
parser.add_argument('-e', '--extensions', dest='extensions',
help='comma-delimited list of extensions used to glob source files',
default="c,cc,cpp,cxx,c++,h,hh,hpp,hxx,h++")
parser.add_argument('-style',
help='formatting style',
default="file")
parser.add_argument('--no-inplace', dest='inplace', action='store_false',
help='do not format files inplace, but write output to the console'
' (useful for debugging)',
default=True)
parser.add_argument('-j', metavar='THREAD_COUNT', type=int, default=0,
help='number of clang-format instances to be run in parallel')
parser.add_argument('-v', '--verbose', action='store_true',
help='output verbose comments')
parser.add_argument(metavar='DIRPATH', dest='directories', nargs='*',
help='path(s) used to glob source files')
args = parser.parse_args(argv[1:])
if not args.directories:
args.directories = [os.getcwd()]
check_clang_format_binary(args)
return args
def _get_format_invocation(args, filename):
invocation = [args.clang_format_binary]
invocation.append('-style=' + args.style)
if args.inplace:
invocation.append('-i')
invocation.append(filename)
return invocation
def check_clang_format_binary(args):
"""Checks if invoking supplied clang-format binary works."""
try:
subprocess.check_output([args.clang_format_binary, '--version'])
except OSError:
print('Unable to run clang-format. Is clang-format '
'binary correctly specified?', file=sys.stderr)
raise
def run_format(args, task_queue, formatted_files):
"""Takes filenames out of queue and runs clang-format on them."""
while True:
filename = task_queue.get()
invocation = _get_format_invocation(args, filename)
if args.verbose:
print('Processing {}'.format(filename))
formatted = subprocess.check_output(invocation)
formatted_files[filename] = formatted
task_queue.task_done()
def format_all(args, files):
max_task = args.j
if max_task == 0:
max_task = multiprocessing.cpu_count()
formatted_files = {}
try:
# Spin up a bunch of format-launching threads.
task_queue = queue.Queue(max_task)
for _ in range(max_task):
task_thread = threading.Thread(target=run_format,
args=(args, task_queue, formatted_files))
task_thread.daemon = True
task_thread.start()
# Fill the queue with files.
for name in files:
task_queue.put(name)
# Wait for all threads to be done.
task_queue.join()
except OSError:
print("Cannot find clang-format at '{}'.".format(args.clang_format_binary),
file=sys.stderr)
raise
except subprocess.CalledProcessError as ex:
print("Running clang-format failed with non-zero status.", file=sys.stderr)
print("Command : {}".format(' '.join(ex.cmd)), file=sys.stderr)
print("Return code: {}".format(str(ex.returncode)), file=sys.stderr)
raise
return formatted_files
def main():
args = parse_args()
files = glob_files(args)
format_all(args, files)
if __name__ == '__main__':
main() # pragma: no cover