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

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

Issue 2542563002: Clang scripts updates. (Closed)
Patch Set: tool-args generalized 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_args, 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_args: Arguments 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 args = [toolname, '-p', build_directory, filename]
139 (toolname, '-p', build_directory, filename), 140 if (tool_args):
140 stdout=subprocess.PIPE, 141 args.extend(tool_args)
141 stderr=subprocess.PIPE) 142 command = subprocess.Popen(tuple(args),
dcheng 2016/12/01 01:09:26 Nit: remove tuple() here, args just needs to be an
Ramin Halavati 2016/12/01 02:32:48 Done.
143 stdout=subprocess.PIPE,
144 stderr=subprocess.PIPE)
142 stdout, stderr = command.communicate() 145 stdout, stderr = command.communicate()
143 if command.returncode != 0: 146 if command.returncode != 0:
144 return {'status': False, 'filename': filename, 'stderr': stderr} 147 return {'status': False, 'filename': filename, 'stderr': stderr}
145 else: 148 else:
146 return {'status': True, 149 return {'status': True,
147 'edits': _ExtractEditsFromStdout(build_directory, stdout)} 150 'edits': _ExtractEditsFromStdout(build_directory, stdout)}
148 151
149 152
150 class _CompilerDispatcher(object): 153 class _CompilerDispatcher(object):
151 """Multiprocessing controller for running clang tools in parallel.""" 154 """Multiprocessing controller for running clang tools in parallel."""
152 155
153 def __init__(self, toolname, build_directory, filenames): 156 def __init__(self, toolname, tool_args, build_directory, filenames):
154 """Initializer method. 157 """Initializer method.
155 158
156 Args: 159 Args:
157 toolname: Path to the tool to execute. 160 toolname: Path to the tool to execute.
161 tool_args: Arguments to be passed to the tool. Can be None.
158 build_directory: Directory that contains the compile database. 162 build_directory: Directory that contains the compile database.
159 filenames: The files to run the tool over. 163 filenames: The files to run the tool over.
160 """ 164 """
161 self.__toolname = toolname 165 self.__toolname = toolname
166 self.__tool_args = tool_args
162 self.__build_directory = build_directory 167 self.__build_directory = build_directory
163 self.__filenames = filenames 168 self.__filenames = filenames
164 self.__success_count = 0 169 self.__success_count = 0
165 self.__failed_count = 0 170 self.__failed_count = 0
166 self.__edit_count = 0 171 self.__edit_count = 0
167 self.__edits = collections.defaultdict(list) 172 self.__edits = collections.defaultdict(list)
168 173
169 @property 174 @property
170 def edits(self): 175 def edits(self):
171 return self.__edits 176 return self.__edits
172 177
173 @property 178 @property
174 def failed_count(self): 179 def failed_count(self):
175 return self.__failed_count 180 return self.__failed_count
176 181
177 def Run(self): 182 def Run(self):
178 """Does the grunt work.""" 183 """Does the grunt work."""
179 pool = multiprocessing.Pool() 184 pool = multiprocessing.Pool()
180 result_iterator = pool.imap_unordered( 185 result_iterator = pool.imap_unordered(
181 functools.partial(_ExecuteTool, self.__toolname, 186 functools.partial(_ExecuteTool, self.__toolname, self.__tool_args,
182 self.__build_directory), self.__filenames) 187 self.__build_directory),
188 self.__filenames)
183 for result in result_iterator: 189 for result in result_iterator:
184 self.__ProcessResult(result) 190 self.__ProcessResult(result)
185 sys.stdout.write('\n') 191 sys.stdout.write('\n')
186 sys.stdout.flush() 192 sys.stdout.flush()
187 193
188 def __ProcessResult(self, result): 194 def __ProcessResult(self, result):
189 """Handles result processing. 195 """Handles result processing.
190 196
191 Args: 197 Args:
192 result: The result dictionary returned by _ExecuteTool. 198 result: The result dictionary returned by _ExecuteTool.
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
292 '--generate-compdb', 298 '--generate-compdb',
293 action='store_true', 299 action='store_true',
294 help='regenerate the compile database before running the tool') 300 help='regenerate the compile database before running the tool')
295 parser.add_argument( 301 parser.add_argument(
296 'compile_database', 302 'compile_database',
297 help='path to the directory that contains the compile database') 303 help='path to the directory that contains the compile database')
298 parser.add_argument( 304 parser.add_argument(
299 'path_filter', 305 'path_filter',
300 nargs='*', 306 nargs='*',
301 help='optional paths to filter what files the tool is run on') 307 help='optional paths to filter what files the tool is run on')
308 parser.add_argument(
309 '--tool-args', nargs='*',
310 help='optional arguments passed to the tool')
302 args = parser.parse_args() 311 args = parser.parse_args()
303 312
304 os.environ['PATH'] = '%s%s%s' % ( 313 os.environ['PATH'] = '%s%s%s' % (
305 os.path.abspath(os.path.join( 314 os.path.abspath(os.path.join(
306 os.path.dirname(__file__), 315 os.path.dirname(__file__),
307 '../../../third_party/llvm-build/Release+Asserts/bin')), 316 '../../../third_party/llvm-build/Release+Asserts/bin')),
308 os.pathsep, 317 os.pathsep,
309 os.environ['PATH']) 318 os.environ['PATH'])
310 319
311 if args.generate_compdb: 320 if args.generate_compdb:
312 compile_db.GenerateWithNinja(args.compile_database) 321 compile_db.GenerateWithNinja(args.compile_database)
313 322
314 if args.all: 323 if args.all:
315 filenames = set(_GetFilesFromCompileDB(args.compile_database)) 324 filenames = set(_GetFilesFromCompileDB(args.compile_database))
316 source_filenames = filenames 325 source_filenames = filenames
317 else: 326 else:
318 filenames = set(_GetFilesFromGit(args.path_filter)) 327 filenames = set(_GetFilesFromGit(args.path_filter))
319 # Filter out files that aren't C/C++/Obj-C/Obj-C++. 328 # Filter out files that aren't C/C++/Obj-C/Obj-C++.
320 extensions = frozenset(('.c', '.cc', '.cpp', '.m', '.mm')) 329 extensions = frozenset(('.c', '.cc', '.cpp', '.m', '.mm'))
321 source_filenames = [f 330 source_filenames = [f
322 for f in filenames 331 for f in filenames
323 if os.path.splitext(f)[1] in extensions] 332 if os.path.splitext(f)[1] in extensions]
324 dispatcher = _CompilerDispatcher(args.tool, args.compile_database, 333 dispatcher = _CompilerDispatcher(args.tool, args.tool_args,
334 args.compile_database,
325 source_filenames) 335 source_filenames)
326 dispatcher.Run() 336 dispatcher.Run()
327 # Filter out edits to files that aren't in the git repository, since it's not 337 # 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 338 # 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. 339 # are generated files or files in a git submodule that's not part of Chromium.
330 _ApplyEdits({k: v 340 _ApplyEdits({k: v
331 for k, v in dispatcher.edits.iteritems() 341 for k, v in dispatcher.edits.iteritems()
332 if os.path.realpath(k) in filenames}) 342 if os.path.realpath(k) in filenames})
333 return -dispatcher.failed_count 343 return -dispatcher.failed_count
334 344
335 345
336 if __name__ == '__main__': 346 if __name__ == '__main__':
337 sys.exit(main()) 347 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