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 298 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
309 line_number = 0 | 309 line_number = 0 |
310 for line in lines: | 310 for line in lines: |
311 line_number += 1 | 311 line_number += 1 |
312 yield (af, line_number, line) | 312 yield (af, line_number, line) |
313 | 313 |
314 | 314 |
315 class AffectedFile(object): | 315 class AffectedFile(object): |
316 """Representation of a file in a change.""" | 316 """Representation of a file in a change.""" |
317 | 317 |
318 def __init__(self, path, action, repository_root=''): | 318 def __init__(self, path, action, repository_root=''): |
319 self.path = path | 319 self._path = path |
320 self.action = action | 320 self._action = action |
321 self.repository_root = repository_root | 321 self._repository_root = repository_root |
322 self.server_path = None | 322 self._is_directory = None |
323 self.is_directory = None | 323 self._properties = {} |
324 self.properties = {} | |
325 | 324 |
326 def ServerPath(self): | 325 def ServerPath(self): |
327 """Returns a path string that identifies the file in the SCM system. | 326 """Returns a path string that identifies the file in the SCM system. |
328 | 327 |
329 Returns the empty string if the file does not exist in SCM. | 328 Returns the empty string if the file does not exist in SCM. |
330 """ | 329 """ |
331 return "" | 330 return "" |
332 | 331 |
333 def LocalPath(self): | 332 def LocalPath(self): |
334 """Returns the path of this file on the local disk relative to client root. | 333 """Returns the path of this file on the local disk relative to client root. |
335 """ | 334 """ |
336 return normpath(self.path) | 335 return normpath(self._path) |
337 | 336 |
338 def AbsoluteLocalPath(self): | 337 def AbsoluteLocalPath(self): |
339 """Returns the absolute path of this file on the local disk. | 338 """Returns the absolute path of this file on the local disk. |
340 """ | 339 """ |
341 return normpath(os.path.join(self.repository_root, self.LocalPath())) | 340 return normpath(os.path.join(self._repository_root, self.LocalPath())) |
342 | 341 |
343 def IsDirectory(self): | 342 def IsDirectory(self): |
344 """Returns true if this object is a directory.""" | 343 """Returns true if this object is a directory.""" |
345 path = self.AbsoluteLocalPath() | 344 if self._is_directory is None: |
346 if self.is_directory is None: | 345 path = self.AbsoluteLocalPath() |
347 self.is_directory = (os.path.exists(path) and | 346 self._is_directory = (os.path.exists(path) and |
348 os.path.isdir(path)) | 347 os.path.isdir(path)) |
349 return self.is_directory | 348 return self._is_directory |
350 | 349 |
351 def Action(self): | 350 def Action(self): |
352 """Returns the action on this opened file, e.g. A, M, D, etc.""" | 351 """Returns the action on this opened file, e.g. A, M, D, etc.""" |
353 # TODO(maruel): Somewhat crappy, Could be "A" or "A +" for svn but | 352 # TODO(maruel): Somewhat crappy, Could be "A" or "A +" for svn but |
354 # different for other SCM. | 353 # different for other SCM. |
355 return self.action | 354 return self._action |
356 | 355 |
357 def Property(self, property_name): | 356 def Property(self, property_name): |
358 """Returns the specified SCM property of this file, or None if no such | 357 """Returns the specified SCM property of this file, or None if no such |
359 property. | 358 property. |
360 """ | 359 """ |
361 return self.properties.get(property_name, None) | 360 return self._properties.get(property_name, None) |
362 | 361 |
363 def IsTextFile(self): | 362 def IsTextFile(self): |
364 """Returns True if the file is a text file and not a binary file.""" | 363 """Returns True if the file is a text file and not a binary file.""" |
365 raise NotImplementedError() # Implement when needed | 364 raise NotImplementedError() # Implement when needed |
366 | 365 |
367 def NewContents(self): | 366 def NewContents(self): |
368 """Returns an iterator over the lines in the new version of file. | 367 """Returns an iterator over the lines in the new version of file. |
369 | 368 |
370 The new version is the file in the user's workspace, i.e. the "right hand | 369 The new version is the file in the user's workspace, i.e. the "right hand |
371 side". | 370 side". |
(...skipping 18 matching lines...) Expand all Loading... |
390 The old version is the file in depot, i.e. the "left hand side". | 389 The old version is the file in depot, i.e. the "left hand side". |
391 This is a read-only cached copy of the old contents. *DO NOT* try to | 390 This is a read-only cached copy of the old contents. *DO NOT* try to |
392 modify this file. | 391 modify this file. |
393 """ | 392 """ |
394 raise NotImplementedError() # Implement if/when needed. | 393 raise NotImplementedError() # Implement if/when needed. |
395 | 394 |
396 | 395 |
397 class SvnAffectedFile(AffectedFile): | 396 class SvnAffectedFile(AffectedFile): |
398 """Representation of a file in a change out of a Subversion checkout.""" | 397 """Representation of a file in a change out of a Subversion checkout.""" |
399 | 398 |
| 399 def __init__(self, *args, **kwargs): |
| 400 AffectedFile.__init__(self, *args, **kwargs) |
| 401 self._server_path = None |
| 402 self._is_text_file = None |
| 403 |
400 def ServerPath(self): | 404 def ServerPath(self): |
401 if self.server_path is None: | 405 if self._server_path is None: |
402 self.server_path = gclient.CaptureSVNInfo( | 406 self._server_path = gclient.CaptureSVNInfo( |
403 self.AbsoluteLocalPath()).get('URL', '') | 407 self.AbsoluteLocalPath()).get('URL', '') |
404 return self.server_path | 408 return self._server_path |
405 | 409 |
406 def IsDirectory(self): | 410 def IsDirectory(self): |
407 path = self.AbsoluteLocalPath() | 411 if self._is_directory is None: |
408 if self.is_directory is None: | 412 path = self.AbsoluteLocalPath() |
409 if os.path.exists(path): | 413 if os.path.exists(path): |
410 # Retrieve directly from the file system; it is much faster than | 414 # Retrieve directly from the file system; it is much faster than |
411 # querying subversion, especially on Windows. | 415 # querying subversion, especially on Windows. |
412 self.is_directory = os.path.isdir(path) | 416 self._is_directory = os.path.isdir(path) |
413 else: | 417 else: |
414 self.is_directory = gclient.CaptureSVNInfo( | 418 self._is_directory = gclient.CaptureSVNInfo( |
415 path).get('Node Kind') in ('dir', 'directory') | 419 path).get('Node Kind') in ('dir', 'directory') |
416 return self.is_directory | 420 return self._is_directory |
417 | 421 |
418 def Property(self, property_name): | 422 def Property(self, property_name): |
419 if not property_name in self.properties: | 423 if not property_name in self._properties: |
420 self.properties[property_name] = gcl.GetSVNFileProperty( | 424 self._properties[property_name] = gcl.GetSVNFileProperty( |
421 self.AbsoluteLocalPath(), property_name) | 425 self.AbsoluteLocalPath(), property_name) |
422 return self.properties[property_name] | 426 return self._properties[property_name] |
423 | 427 |
424 def IsTextFile(self): | 428 def IsTextFile(self): |
425 if self.Action() == 'D': | 429 if self._is_text_file is None: |
426 return False | 430 if self.Action() == 'D': |
427 mime_type = gcl.GetSVNFileProperty(self.AbsoluteLocalPath(), | 431 # A deleted file is not a text file. |
428 'svn:mime-type') | 432 self._is_text_file = False |
429 if not mime_type or mime_type.startswith('text/'): | 433 elif self.IsDirectory(): |
430 return True | 434 self._is_text_file = False |
431 return False | 435 else: |
| 436 mime_type = gcl.GetSVNFileProperty(self.AbsoluteLocalPath(), |
| 437 'svn:mime-type') |
| 438 self._is_text_file = (not mime_type or mime_type.startswith('text/')) |
| 439 return self._is_text_file |
432 | 440 |
433 | 441 |
434 class GclChange(object): | 442 class GclChange(object): |
435 """Describe a change. | 443 """Describe a change. |
436 | 444 |
437 Used directly by the presubmit scripts to query the current change being | 445 Used directly by the presubmit scripts to query the current change being |
438 tested. | 446 tested. |
439 | 447 |
440 Instance members: | 448 Instance members: |
441 tags: Dictionnary of KEY=VALUE pairs found in the change description. | 449 tags: Dictionnary of KEY=VALUE pairs found in the change description. |
(...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
755 return not DoPresubmitChecks(gcl.ChangeInfo(name='temp', files=files), | 763 return not DoPresubmitChecks(gcl.ChangeInfo(name='temp', files=files), |
756 options.commit, | 764 options.commit, |
757 options.verbose, | 765 options.verbose, |
758 sys.stdout, | 766 sys.stdout, |
759 sys.stdin, | 767 sys.stdin, |
760 default_presubmit=None) | 768 default_presubmit=None) |
761 | 769 |
762 | 770 |
763 if __name__ == '__main__': | 771 if __name__ == '__main__': |
764 sys.exit(Main(sys.argv)) | 772 sys.exit(Main(sys.argv)) |
OLD | NEW |