| 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 |