OLD | NEW |
1 #!/usr/bin/python | 1 #!/usr/bin/python |
2 # Copyright (c) 2006-2009 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2006-2009 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 """Enables directory-specific presubmit checks to run at upload and/or commit. | 6 """Enables directory-specific presubmit checks to run at upload and/or commit. |
7 """ | 7 """ |
8 | 8 |
9 __version__ = '1.1' | 9 __version__ = '1.1' |
10 | 10 |
(...skipping 204 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
215 Args: | 215 Args: |
216 Local path (relative to current directory, or absolute) as a string. | 216 Local path (relative to current directory, or absolute) as a string. |
217 | 217 |
218 Returns: | 218 Returns: |
219 The depot path (SVN URL) of the file if mapped, otherwise None. | 219 The depot path (SVN URL) of the file if mapped, otherwise None. |
220 """ | 220 """ |
221 depot_path = gclient.CaptureSVNInfo(local_path).get('URL') | 221 depot_path = gclient.CaptureSVNInfo(local_path).get('URL') |
222 if depot_path: | 222 if depot_path: |
223 return depot_path | 223 return depot_path |
224 | 224 |
225 @staticmethod | |
226 def FilterTextFiles(affected_files, include_deletes=True): | |
227 """Filters out all except text files and optionally also filters out | |
228 deleted files. | |
229 | |
230 Args: | |
231 affected_files: List of AffectedFiles objects. | |
232 include_deletes: If false, deleted files will be filtered out. | |
233 | |
234 Returns: | |
235 Filtered list of AffectedFiles objects. | |
236 """ | |
237 output_files = [] | |
238 for af in affected_files: | |
239 if include_deletes or af.Action() != 'D': | |
240 path = af.AbsoluteLocalPath() | |
241 mime_type = gcl.GetSVNFileProperty(path, 'svn:mime-type') | |
242 if not mime_type or mime_type.startswith('text/'): | |
243 output_files.append(af) | |
244 return output_files | |
245 | |
246 def AffectedFiles(self, include_dirs=False, include_deletes=True): | 225 def AffectedFiles(self, include_dirs=False, include_deletes=True): |
247 """Same as input_api.change.AffectedFiles() except only lists files | 226 """Same as input_api.change.AffectedFiles() except only lists files |
248 (and optionally directories) in the same directory as the current presubmit | 227 (and optionally directories) in the same directory as the current presubmit |
249 script, or subdirectories thereof. | 228 script, or subdirectories thereof. |
250 """ | 229 """ |
251 output_files = [] | |
252 dir_with_slash = normpath("%s/" % self.PresubmitLocalPath()) | 230 dir_with_slash = normpath("%s/" % self.PresubmitLocalPath()) |
253 if len(dir_with_slash) == 1: | 231 if len(dir_with_slash) == 1: |
254 dir_with_slash = '' | 232 dir_with_slash = '' |
255 for af in self.change.AffectedFiles(include_dirs, include_deletes): | 233 return filter(lambda x: normpath(x.LocalPath()).startswith(dir_with_slash), |
256 af_path = normpath(af.LocalPath()) | 234 self.change.AffectedFiles(include_dirs, include_deletes)) |
257 if af_path.startswith(dir_with_slash): | |
258 output_files.append(af) | |
259 return output_files | |
260 | 235 |
261 def LocalPaths(self, include_dirs=False): | 236 def LocalPaths(self, include_dirs=False): |
262 """Returns local paths of input_api.AffectedFiles().""" | 237 """Returns local paths of input_api.AffectedFiles().""" |
263 return [af.LocalPath() for af in self.AffectedFiles(include_dirs)] | 238 return [af.LocalPath() for af in self.AffectedFiles(include_dirs)] |
264 | 239 |
265 def AbsoluteLocalPaths(self, include_dirs=False): | 240 def AbsoluteLocalPaths(self, include_dirs=False): |
266 """Returns absolute local paths of input_api.AffectedFiles().""" | 241 """Returns absolute local paths of input_api.AffectedFiles().""" |
267 return [af.AbsoluteLocalPath() for af in self.AffectedFiles(include_dirs)] | 242 return [af.AbsoluteLocalPath() for af in self.AffectedFiles(include_dirs)] |
268 | 243 |
269 def ServerPaths(self, include_dirs=False): | 244 def ServerPaths(self, include_dirs=False): |
270 """Returns server paths of input_api.AffectedFiles().""" | 245 """Returns server paths of input_api.AffectedFiles().""" |
271 return [af.ServerPath() for af in self.AffectedFiles(include_dirs)] | 246 return [af.ServerPath() for af in self.AffectedFiles(include_dirs)] |
272 | 247 |
273 @deprecated | 248 def AffectedTextFiles(self, include_deletes=None): |
274 def AffectedTextFiles(self, include_deletes=True): | |
275 """Same as input_api.change.AffectedTextFiles() except only lists files | 249 """Same as input_api.change.AffectedTextFiles() except only lists files |
276 in the same directory as the current presubmit script, or subdirectories | 250 in the same directory as the current presubmit script, or subdirectories |
277 thereof. | 251 thereof. |
278 | |
279 Warning: This function retrieves the svn property on each file so it can be | |
280 slow for large change lists. | |
281 """ | 252 """ |
282 return InputApi.FilterTextFiles(self.AffectedFiles(include_dirs=False), | 253 if include_deletes is not None: |
283 include_deletes) | 254 warnings.warn("AffectedTextFiles(include_deletes=%s)" |
| 255 " is deprecated and ignored" % str(include_deletes), |
| 256 category=DeprecationWarning, |
| 257 stacklevel=2) |
| 258 return filter(lambda x: x.IsTextFile(), |
| 259 self.AffectedFiles(include_dirs=False, include_deletes=False)) |
284 | 260 |
285 def RightHandSideLines(self): | 261 def RightHandSideLines(self): |
286 """An iterator over all text lines in "new" version of changed files. | 262 """An iterator over all text lines in "new" version of changed files. |
287 | 263 |
288 Only lists lines from new or modified text files in the change that are | 264 Only lists lines from new or modified text files in the change that are |
289 contained by the directory of the currently executing presubmit script. | 265 contained by the directory of the currently executing presubmit script. |
290 | 266 |
291 This is useful for doing line-by-line regex checks, like checking for | 267 This is useful for doing line-by-line regex checks, like checking for |
292 trailing whitespace. | 268 trailing whitespace. |
293 | 269 |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
353 # different for other SCM. | 329 # different for other SCM. |
354 return self._action | 330 return self._action |
355 | 331 |
356 def Property(self, property_name): | 332 def Property(self, property_name): |
357 """Returns the specified SCM property of this file, or None if no such | 333 """Returns the specified SCM property of this file, or None if no such |
358 property. | 334 property. |
359 """ | 335 """ |
360 return self._properties.get(property_name, None) | 336 return self._properties.get(property_name, None) |
361 | 337 |
362 def IsTextFile(self): | 338 def IsTextFile(self): |
363 """Returns True if the file is a text file and not a binary file.""" | 339 """Returns True if the file is a text file and not a binary file. |
| 340 |
| 341 Deleted files are not text file.""" |
364 raise NotImplementedError() # Implement when needed | 342 raise NotImplementedError() # Implement when needed |
365 | 343 |
366 def NewContents(self): | 344 def NewContents(self): |
367 """Returns an iterator over the lines in the new version of file. | 345 """Returns an iterator over the lines in the new version of file. |
368 | 346 |
369 The new version is the file in the user's workspace, i.e. the "right hand | 347 The new version is the file in the user's workspace, i.e. the "right hand |
370 side". | 348 side". |
371 | 349 |
372 Contents will be empty if the file is a directory or does not exist. | 350 Contents will be empty if the file is a directory or does not exist. |
373 """ | 351 """ |
(...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 if include_dirs: | 500 if include_dirs: |
523 affected = self._affected_files | 501 affected = self._affected_files |
524 else: | 502 else: |
525 affected = filter(lambda x: not x.IsDirectory(), self._affected_files) | 503 affected = filter(lambda x: not x.IsDirectory(), self._affected_files) |
526 | 504 |
527 if include_deletes: | 505 if include_deletes: |
528 return affected | 506 return affected |
529 else: | 507 else: |
530 return filter(lambda x: x.Action() != 'D', affected) | 508 return filter(lambda x: x.Action() != 'D', affected) |
531 | 509 |
532 @deprecated | 510 def AffectedTextFiles(self, include_deletes=None): |
533 def AffectedTextFiles(self, include_deletes=True): | 511 """Return a list of the existing text files in a change.""" |
534 """Return a list of the text files in a change. | 512 if include_deletes is not None: |
535 | 513 warnings.warn("AffectedTextFiles(include_deletes=%s)" |
536 It's common to want to iterate over only the text files. | 514 " is deprecated and ignored" % str(include_deletes), |
537 | 515 category=DeprecationWarning, |
538 Args: | 516 stacklevel=2) |
539 include_deletes: Controls whether to return files with "delete" actions, | 517 return filter(lambda x: x.IsTextFile(), |
540 which commonly aren't relevant to presubmit scripts. | 518 self.AffectedFiles(include_dirs=False, include_deletes=False)) |
541 """ | |
542 return InputApi.FilterTextFiles(self.AffectedFiles(include_dirs=False), | |
543 include_deletes) | |
544 | 519 |
545 def LocalPaths(self, include_dirs=False): | 520 def LocalPaths(self, include_dirs=False): |
546 """Convenience function.""" | 521 """Convenience function.""" |
547 return [af.LocalPath() for af in self.AffectedFiles(include_dirs)] | 522 return [af.LocalPath() for af in self.AffectedFiles(include_dirs)] |
548 | 523 |
549 def AbsoluteLocalPaths(self, include_dirs=False): | 524 def AbsoluteLocalPaths(self, include_dirs=False): |
550 """Convenience function.""" | 525 """Convenience function.""" |
551 return [af.AbsoluteLocalPath() for af in self.AffectedFiles(include_dirs)] | 526 return [af.AbsoluteLocalPath() for af in self.AffectedFiles(include_dirs)] |
552 | 527 |
553 def ServerPaths(self, include_dirs=False): | 528 def ServerPaths(self, include_dirs=False): |
(...skipping 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
763 return not DoPresubmitChecks(gcl.ChangeInfo(name='temp', files=files), | 738 return not DoPresubmitChecks(gcl.ChangeInfo(name='temp', files=files), |
764 options.commit, | 739 options.commit, |
765 options.verbose, | 740 options.verbose, |
766 sys.stdout, | 741 sys.stdout, |
767 sys.stdin, | 742 sys.stdin, |
768 default_presubmit=None) | 743 default_presubmit=None) |
769 | 744 |
770 | 745 |
771 if __name__ == '__main__': | 746 if __name__ == '__main__': |
772 sys.exit(Main(sys.argv)) | 747 sys.exit(Main(sys.argv)) |
OLD | NEW |