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

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

Issue 723343002: Update from https://crrev.com/304121 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 6 years, 1 month 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
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 5
6 """Wrapper script to help run clang tools across Chromium code. 6 """Wrapper script to help run clang tools across Chromium code.
7 7
8 How to use this tool: 8 How to use this tool:
9 If you want to run the tool across all Chromium code: 9 If you want to run the tool across all Chromium code:
10 run_tool.py <tool> <path/to/compiledb> 10 run_tool.py <tool> <path/to/compiledb>
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 Edit = collections.namedtuple( 47 Edit = collections.namedtuple(
48 'Edit', ('edit_type', 'offset', 'length', 'replacement')) 48 'Edit', ('edit_type', 'offset', 'length', 'replacement'))
49 49
50 50
51 def _GetFilesFromGit(paths = None): 51 def _GetFilesFromGit(paths = None):
52 """Gets the list of files in the git repository. 52 """Gets the list of files in the git repository.
53 53
54 Args: 54 Args:
55 paths: Prefix filter for the returned paths. May contain multiple entries. 55 paths: Prefix filter for the returned paths. May contain multiple entries.
56 """ 56 """
57 args = ['git', 'ls-files'] 57 args = []
58 if sys.platform == 'win32':
59 args.append('git.bat')
60 else:
61 args.append('git')
62 args.append('ls-files')
58 if paths: 63 if paths:
59 args.extend(paths) 64 args.extend(paths)
60 command = subprocess.Popen(args, stdout=subprocess.PIPE) 65 command = subprocess.Popen(args, stdout=subprocess.PIPE)
61 output, _ = command.communicate() 66 output, _ = command.communicate()
62 return output.splitlines() 67 return [os.path.realpath(p) for p in output.splitlines()]
63 68
64 69
65 def _ExtractEditsFromStdout(build_directory, stdout): 70 def _ExtractEditsFromStdout(build_directory, stdout):
66 """Extracts generated list of edits from the tool's stdout. 71 """Extracts generated list of edits from the tool's stdout.
67 72
68 The expected format is documented at the top of this file. 73 The expected format is documented at the top of this file.
69 74
70 Args: 75 Args:
71 build_directory: Directory that contains the compile database. Used to 76 build_directory: Directory that contains the compile database. Used to
72 normalize the filenames. 77 normalize the filenames.
73 stdout: The stdout from running the clang tool. 78 stdout: The stdout from running the clang tool.
74 79
75 Returns: 80 Returns:
76 A dictionary mapping filenames to the associated edits. 81 A dictionary mapping filenames to the associated edits.
77 """ 82 """
78 lines = stdout.splitlines() 83 lines = stdout.splitlines()
79 start_index = lines.index('==== BEGIN EDITS ====') 84 start_index = lines.index('==== BEGIN EDITS ====')
80 end_index = lines.index('==== END EDITS ====') 85 end_index = lines.index('==== END EDITS ====')
81 edits = collections.defaultdict(list) 86 edits = collections.defaultdict(list)
82 for line in lines[start_index + 1:end_index]: 87 for line in lines[start_index + 1:end_index]:
83 try: 88 try:
84 edit_type, path, offset, length, replacement = line.split(':', 4) 89 edit_type, path, offset, length, replacement = line.split(':::', 4)
85 replacement = replacement.replace("\0", "\n"); 90 replacement = replacement.replace("\0", "\n");
86 # Normalize the file path emitted by the clang tool to be relative to the 91 # Normalize the file path emitted by the clang tool.
87 # current working directory. 92 path = os.path.realpath(os.path.join(build_directory, path))
88 path = os.path.relpath(os.path.join(build_directory, path))
89 edits[path].append(Edit(edit_type, int(offset), int(length), replacement)) 93 edits[path].append(Edit(edit_type, int(offset), int(length), replacement))
90 except ValueError: 94 except ValueError:
91 print 'Unable to parse edit: %s' % line 95 print 'Unable to parse edit: %s' % line
92 return edits 96 return edits
93 97
94 98
95 def _ExecuteTool(toolname, build_directory, filename): 99 def _ExecuteTool(toolname, build_directory, filename):
96 """Executes the tool. 100 """Executes the tool.
97 101
98 This is defined outside the class so it can be pickled for the multiprocessing 102 This is defined outside the class so it can be pickled for the multiprocessing
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 Args: 137 Args:
134 toolname: Path to the tool to execute. 138 toolname: Path to the tool to execute.
135 build_directory: Directory that contains the compile database. 139 build_directory: Directory that contains the compile database.
136 filenames: The files to run the tool over. 140 filenames: The files to run the tool over.
137 """ 141 """
138 self.__toolname = toolname 142 self.__toolname = toolname
139 self.__build_directory = build_directory 143 self.__build_directory = build_directory
140 self.__filenames = filenames 144 self.__filenames = filenames
141 self.__success_count = 0 145 self.__success_count = 0
142 self.__failed_count = 0 146 self.__failed_count = 0
147 self.__edit_count = 0
143 self.__edits = collections.defaultdict(list) 148 self.__edits = collections.defaultdict(list)
144 149
145 @property 150 @property
146 def edits(self): 151 def edits(self):
147 return self.__edits 152 return self.__edits
148 153
149 @property 154 @property
150 def failed_count(self): 155 def failed_count(self):
151 return self.__failed_count 156 return self.__failed_count
152 157
(...skipping 12 matching lines...) Expand all
165 def __ProcessResult(self, result): 170 def __ProcessResult(self, result):
166 """Handles result processing. 171 """Handles result processing.
167 172
168 Args: 173 Args:
169 result: The result dictionary returned by _ExecuteTool. 174 result: The result dictionary returned by _ExecuteTool.
170 """ 175 """
171 if result['status']: 176 if result['status']:
172 self.__success_count += 1 177 self.__success_count += 1
173 for k, v in result['edits'].iteritems(): 178 for k, v in result['edits'].iteritems():
174 self.__edits[k].extend(v) 179 self.__edits[k].extend(v)
180 self.__edit_count += len(v)
175 else: 181 else:
176 self.__failed_count += 1 182 self.__failed_count += 1
177 sys.stdout.write('\nFailed to process %s\n' % result['filename']) 183 sys.stdout.write('\nFailed to process %s\n' % result['filename'])
178 sys.stdout.write(result['stderr']) 184 sys.stdout.write(result['stderr'])
179 sys.stdout.write('\n') 185 sys.stdout.write('\n')
180 percentage = ( 186 percentage = (
181 float(self.__success_count + self.__failed_count) / 187 float(self.__success_count + self.__failed_count) /
182 len(self.__filenames)) * 100 188 len(self.__filenames)) * 100
183 sys.stdout.write('Succeeded: %d, Failed: %d [%.2f%%]\r' % ( 189 sys.stdout.write('Succeeded: %d, Failed: %d, Edits: %d [%.2f%%]\r' % (
184 self.__success_count, self.__failed_count, percentage)) 190 self.__success_count, self.__failed_count, self.__edit_count,
191 percentage))
185 sys.stdout.flush() 192 sys.stdout.flush()
186 193
187 194
188 def _ApplyEdits(edits, clang_format_diff_path): 195 def _ApplyEdits(edits, clang_format_diff_path):
189 """Apply the generated edits. 196 """Apply the generated edits.
190 197
191 Args: 198 Args:
192 edits: A dict mapping filenames to Edit instances that apply to that file. 199 edits: A dict mapping filenames to Edit instances that apply to that file.
193 clang_format_diff_path: Path to the clang-format-diff.py helper to help 200 clang_format_diff_path: Path to the clang-format-diff.py helper to help
194 automatically reformat diffs to avoid style violations. Pass None if the 201 automatically reformat diffs to avoid style violations. Pass None if the
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 print ' <clang tool> is the clang tool that should be run.' 283 print ' <clang tool> is the clang tool that should be run.'
277 print ' <compile db> is the directory that contains the compile database' 284 print ' <compile db> is the directory that contains the compile database'
278 print ' <path 1> <path2> ... can be used to filter what files are edited' 285 print ' <path 1> <path2> ... can be used to filter what files are edited'
279 return 1 286 return 1
280 287
281 clang_format_diff_path = os.path.join( 288 clang_format_diff_path = os.path.join(
282 os.path.dirname(os.path.realpath(__file__)), 289 os.path.dirname(os.path.realpath(__file__)),
283 '../../../third_party/llvm/tools/clang/tools/clang-format', 290 '../../../third_party/llvm/tools/clang/tools/clang-format',
284 'clang-format-diff.py') 291 'clang-format-diff.py')
285 # TODO(dcheng): Allow this to be controlled with a flag as well. 292 # TODO(dcheng): Allow this to be controlled with a flag as well.
286 if not os.path.isfile(clang_format_diff_path): 293 # TODO(dcheng): Shell escaping of args to git diff to clang-format is broken
294 # on Windows.
295 if not os.path.isfile(clang_format_diff_path) or sys.platform == 'win32':
287 clang_format_diff_path = None 296 clang_format_diff_path = None
288 297
289 filenames = frozenset(_GetFilesFromGit(argv[2:])) 298 filenames = frozenset(_GetFilesFromGit(argv[2:]))
290 # Filter out files that aren't C/C++/Obj-C/Obj-C++. 299 # Filter out files that aren't C/C++/Obj-C/Obj-C++.
291 extensions = frozenset(('.c', '.cc', '.m', '.mm')) 300 extensions = frozenset(('.c', '.cc', '.m', '.mm'))
292 dispatcher = _CompilerDispatcher(argv[0], argv[1], 301 dispatcher = _CompilerDispatcher(argv[0], argv[1],
293 [f for f in filenames 302 [f for f in filenames
294 if os.path.splitext(f)[1] in extensions]) 303 if os.path.splitext(f)[1] in extensions])
295 dispatcher.Run() 304 dispatcher.Run()
296 # Filter out edits to files that aren't in the git repository, since it's not 305 # Filter out edits to files that aren't in the git repository, since it's not
297 # useful to modify files that aren't under source control--typically, these 306 # useful to modify files that aren't under source control--typically, these
298 # are generated files or files in a git submodule that's not part of Chromium. 307 # are generated files or files in a git submodule that's not part of Chromium.
299 _ApplyEdits({k : v for k, v in dispatcher.edits.iteritems() 308 _ApplyEdits({k : v for k, v in dispatcher.edits.iteritems()
300 if k in filenames}, 309 if os.path.realpath(k) in filenames},
301 clang_format_diff_path) 310 clang_format_diff_path)
302 if dispatcher.failed_count != 0: 311 if dispatcher.failed_count != 0:
303 return 2 312 return 2
304 return 0 313 return 0
305 314
306 315
307 if __name__ == '__main__': 316 if __name__ == '__main__':
308 sys.exit(main(sys.argv[1:])) 317 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp ('k') | tools/clang/scripts/test_tool.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698