Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(49)

Side by Side Diff: tools/clang/scripts/run_tool.py

Issue 2542563002: Clang scripts updates. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/clang/scripts/generate_win_compdb.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 """Wrapper script to help run clang tools across Chromium code. 5 """Wrapper script to help run clang tools across Chromium code.
6 6
7 How to use this tool: 7 How to use this tool:
8 If you want to run the tool across all Chromium code: 8 If you want to run the tool across all Chromium code:
9 run_tool.py <tool> <path/to/compiledb> 9 run_tool.py <tool> <path/to/compiledb>
10 10
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
107 edit_type, path, offset, length, replacement = line.split(':::', 4) 107 edit_type, path, offset, length, replacement = line.split(':::', 4)
108 replacement = replacement.replace('\0', '\n') 108 replacement = replacement.replace('\0', '\n')
109 # Normalize the file path emitted by the clang tool. 109 # Normalize the file path emitted by the clang tool.
110 path = os.path.realpath(os.path.join(build_directory, path)) 110 path = os.path.realpath(os.path.join(build_directory, path))
111 edits[path].append(Edit(edit_type, int(offset), int(length), replacement)) 111 edits[path].append(Edit(edit_type, int(offset), int(length), replacement))
112 except ValueError: 112 except ValueError:
113 print 'Unable to parse edit: %s' % line 113 print 'Unable to parse edit: %s' % line
114 return edits 114 return edits
115 115
116 116
117 def _ExecuteTool(toolname, build_directory, filename): 117 def _ExecuteTool(toolname, tool_param, build_directory, filename):
118 """Executes the tool. 118 """Executes the tool.
119 119
120 This is defined outside the class so it can be pickled for the multiprocessing 120 This is defined outside the class so it can be pickled for the multiprocessing
121 module. 121 module.
122 122
123 Args: 123 Args:
124 toolname: Path to the tool to execute. 124 toolname: Path to the tool to execute.
125 tool_param: Parameter to be passed to the tool. Can be None.
125 build_directory: Directory that contains the compile database. 126 build_directory: Directory that contains the compile database.
126 filename: The file to run the tool over. 127 filename: The file to run the tool over.
127 128
128 Returns: 129 Returns:
129 A dictionary that must contain the key "status" and a boolean value 130 A dictionary that must contain the key "status" and a boolean value
130 associated with it. 131 associated with it.
131 132
132 If status is True, then the generated edits are stored with the key "edits" 133 If status is True, then the generated edits are stored with the key "edits"
133 in the dictionary. 134 in the dictionary.
134 135
135 Otherwise, the filename and the output from stderr are associated with the 136 Otherwise, the filename and the output from stderr are associated with the
136 keys "filename" and "stderr" respectively. 137 keys "filename" and "stderr" respectively.
137 """ 138 """
138 command = subprocess.Popen( 139 command = subprocess.Popen(
139 (toolname, '-p', build_directory, filename), 140 (toolname, '-p', build_directory, filename) if tool_param is None else
141 (toolname, '-p', build_directory, filename, tool_param),
140 stdout=subprocess.PIPE, 142 stdout=subprocess.PIPE,
141 stderr=subprocess.PIPE) 143 stderr=subprocess.PIPE)
142 stdout, stderr = command.communicate() 144 stdout, stderr = command.communicate()
143 if command.returncode != 0: 145 if command.returncode != 0:
144 return {'status': False, 'filename': filename, 'stderr': stderr} 146 return {'status': False, 'filename': filename, 'stderr': stderr}
145 else: 147 else:
146 return {'status': True, 148 return {'status': True,
147 'edits': _ExtractEditsFromStdout(build_directory, stdout)} 149 'edits': _ExtractEditsFromStdout(build_directory, stdout)}
148 150
149 151
150 class _CompilerDispatcher(object): 152 class _CompilerDispatcher(object):
151 """Multiprocessing controller for running clang tools in parallel.""" 153 """Multiprocessing controller for running clang tools in parallel."""
152 154
153 def __init__(self, toolname, build_directory, filenames): 155 def __init__(self, toolname, tool_param, build_directory, filenames):
154 """Initializer method. 156 """Initializer method.
155 157
156 Args: 158 Args:
157 toolname: Path to the tool to execute. 159 toolname: Path to the tool to execute.
160 tool_param: Parameter to be passed to the tool. Can be None.
158 build_directory: Directory that contains the compile database. 161 build_directory: Directory that contains the compile database.
159 filenames: The files to run the tool over. 162 filenames: The files to run the tool over.
160 """ 163 """
161 self.__toolname = toolname 164 self.__toolname = toolname
165 self.__tool_param = tool_param
162 self.__build_directory = build_directory 166 self.__build_directory = build_directory
163 self.__filenames = filenames 167 self.__filenames = filenames
164 self.__success_count = 0 168 self.__success_count = 0
165 self.__failed_count = 0 169 self.__failed_count = 0
166 self.__edit_count = 0 170 self.__edit_count = 0
167 self.__edits = collections.defaultdict(list) 171 self.__edits = collections.defaultdict(list)
168 172
169 @property 173 @property
170 def edits(self): 174 def edits(self):
171 return self.__edits 175 return self.__edits
172 176
173 @property 177 @property
174 def failed_count(self): 178 def failed_count(self):
175 return self.__failed_count 179 return self.__failed_count
176 180
177 def Run(self): 181 def Run(self):
178 """Does the grunt work.""" 182 """Does the grunt work."""
179 pool = multiprocessing.Pool() 183 pool = multiprocessing.Pool()
180 result_iterator = pool.imap_unordered( 184 result_iterator = pool.imap_unordered(
181 functools.partial(_ExecuteTool, self.__toolname, 185 functools.partial(_ExecuteTool, self.__toolname, self.__tool_param,
182 self.__build_directory), self.__filenames) 186 self.__build_directory),
187 self.__filenames)
183 for result in result_iterator: 188 for result in result_iterator:
184 self.__ProcessResult(result) 189 self.__ProcessResult(result)
185 sys.stdout.write('\n') 190 sys.stdout.write('\n')
186 sys.stdout.flush() 191 sys.stdout.flush()
187 192
188 def __ProcessResult(self, result): 193 def __ProcessResult(self, result):
189 """Handles result processing. 194 """Handles result processing.
190 195
191 Args: 196 Args:
192 result: The result dictionary returned by _ExecuteTool. 197 result: The result dictionary returned by _ExecuteTool.
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 '--generate-compdb', 297 '--generate-compdb',
293 action='store_true', 298 action='store_true',
294 help='regenerate the compile database before running the tool') 299 help='regenerate the compile database before running the tool')
295 parser.add_argument( 300 parser.add_argument(
296 'compile_database', 301 'compile_database',
297 help='path to the directory that contains the compile database') 302 help='path to the directory that contains the compile database')
298 parser.add_argument( 303 parser.add_argument(
299 'path_filter', 304 'path_filter',
300 nargs='*', 305 nargs='*',
301 help='optional paths to filter what files the tool is run on') 306 help='optional paths to filter what files the tool is run on')
307 parser.add_argument(
308 '--tool-param', type=str,
dcheng 2016/11/30 05:19:20 Nit: the default is string already.
309 help='optional parameter passed to the tool')
302 args = parser.parse_args() 310 args = parser.parse_args()
303 311
304 os.environ['PATH'] = '%s%s%s' % ( 312 os.environ['PATH'] = '%s%s%s' % (
305 os.path.abspath(os.path.join( 313 os.path.abspath(os.path.join(
306 os.path.dirname(__file__), 314 os.path.dirname(__file__),
307 '../../../third_party/llvm-build/Release+Asserts/bin')), 315 '../../../third_party/llvm-build/Release+Asserts/bin')),
308 os.pathsep, 316 os.pathsep,
309 os.environ['PATH']) 317 os.environ['PATH'])
310 318
311 if args.generate_compdb: 319 if args.generate_compdb:
312 compile_db.GenerateWithNinja(args.compile_database) 320 compile_db.GenerateWithNinja(args.compile_database)
313 321
314 if args.all: 322 if args.all:
315 filenames = set(_GetFilesFromCompileDB(args.compile_database)) 323 filenames = set(_GetFilesFromCompileDB(args.compile_database))
316 source_filenames = filenames 324 source_filenames = filenames
317 else: 325 else:
318 filenames = set(_GetFilesFromGit(args.path_filter)) 326 filenames = set(_GetFilesFromGit(args.path_filter))
319 # Filter out files that aren't C/C++/Obj-C/Obj-C++. 327 # Filter out files that aren't C/C++/Obj-C/Obj-C++.
320 extensions = frozenset(('.c', '.cc', '.cpp', '.m', '.mm')) 328 extensions = frozenset(('.c', '.cc', '.cpp', '.m', '.mm'))
321 source_filenames = [f 329 source_filenames = [f
322 for f in filenames 330 for f in filenames
323 if os.path.splitext(f)[1] in extensions] 331 if os.path.splitext(f)[1] in extensions]
324 dispatcher = _CompilerDispatcher(args.tool, args.compile_database, 332 dispatcher = _CompilerDispatcher(args.tool, args.tool_param,
333 args.compile_database,
325 source_filenames) 334 source_filenames)
326 dispatcher.Run() 335 dispatcher.Run()
327 # Filter out edits to files that aren't in the git repository, since it's not 336 # Filter out edits to files that aren't in the git repository, since it's not
328 # useful to modify files that aren't under source control--typically, these 337 # useful to modify files that aren't under source control--typically, these
329 # are generated files or files in a git submodule that's not part of Chromium. 338 # are generated files or files in a git submodule that's not part of Chromium.
330 _ApplyEdits({k: v 339 _ApplyEdits({k: v
331 for k, v in dispatcher.edits.iteritems() 340 for k, v in dispatcher.edits.iteritems()
332 if os.path.realpath(k) in filenames}) 341 if os.path.realpath(k) in filenames})
333 return -dispatcher.failed_count 342 return -dispatcher.failed_count
334 343
335 344
336 if __name__ == '__main__': 345 if __name__ == '__main__':
337 sys.exit(main()) 346 sys.exit(main())
OLDNEW
« no previous file with comments | « tools/clang/scripts/generate_win_compdb.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698