| OLD | NEW | 
|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python | 
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 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.8.0' | 9 __version__ = '1.8.0' | 
| 10 | 10 | 
| (...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 487 | 487 | 
| 488     The lists will be compiled as regular expression and | 488     The lists will be compiled as regular expression and | 
| 489     AffectedFile.LocalPath() needs to pass both list. | 489     AffectedFile.LocalPath() needs to pass both list. | 
| 490 | 490 | 
| 491     Note: Copy-paste this function to suit your needs or use a lambda function. | 491     Note: Copy-paste this function to suit your needs or use a lambda function. | 
| 492     """ | 492     """ | 
| 493     def Find(affected_file, items): | 493     def Find(affected_file, items): | 
| 494       local_path = affected_file.LocalPath() | 494       local_path = affected_file.LocalPath() | 
| 495       for item in items: | 495       for item in items: | 
| 496         if self.re.match(item, local_path): | 496         if self.re.match(item, local_path): | 
| 497           logging.debug("%s matched %s" % (item, local_path)) | 497           logging.debug("%s matched %s", item, local_path) | 
| 498           return True | 498           return True | 
| 499       return False | 499       return False | 
| 500     return (Find(affected_file, white_list or self.DEFAULT_WHITE_LIST) and | 500     return (Find(affected_file, white_list or self.DEFAULT_WHITE_LIST) and | 
| 501             not Find(affected_file, black_list or self.DEFAULT_BLACK_LIST)) | 501             not Find(affected_file, black_list or self.DEFAULT_BLACK_LIST)) | 
| 502 | 502 | 
| 503   def AffectedSourceFiles(self, source_file): | 503   def AffectedSourceFiles(self, source_file): | 
| 504     """Filter the list of AffectedTextFiles by the function source_file. | 504     """Filter the list of AffectedTextFiles by the function source_file. | 
| 505 | 505 | 
| 506     If source_file is None, InputApi.FilterSourceFile() is used. | 506     If source_file is None, InputApi.FilterSourceFile() is used. | 
| 507     """ | 507     """ | 
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 639   # pylint: disable=R0201 | 639   # pylint: disable=R0201 | 
| 640   def __init__(self, path, action, repository_root, diff_cache): | 640   def __init__(self, path, action, repository_root, diff_cache): | 
| 641     self._path = path | 641     self._path = path | 
| 642     self._action = action | 642     self._action = action | 
| 643     self._local_root = repository_root | 643     self._local_root = repository_root | 
| 644     self._is_directory = None | 644     self._is_directory = None | 
| 645     self._properties = {} | 645     self._properties = {} | 
| 646     self._cached_changed_contents = None | 646     self._cached_changed_contents = None | 
| 647     self._cached_new_contents = None | 647     self._cached_new_contents = None | 
| 648     self._diff_cache = diff_cache | 648     self._diff_cache = diff_cache | 
| 649     logging.debug('%s(%s)' % (self.__class__.__name__, self._path)) | 649     logging.debug('%s(%s)', self.__class__.__name__, self._path) | 
| 650 | 650 | 
| 651   def ServerPath(self): | 651   def ServerPath(self): | 
| 652     """Returns a path string that identifies the file in the SCM system. | 652     """Returns a path string that identifies the file in the SCM system. | 
| 653 | 653 | 
| 654     Returns the empty string if the file does not exist in SCM. | 654     Returns the empty string if the file does not exist in SCM. | 
| 655     """ | 655     """ | 
| 656     return '' | 656     return '' | 
| 657 | 657 | 
| 658   def LocalPath(self): | 658   def LocalPath(self): | 
| 659     """Returns the path of this file on the local disk relative to client root. | 659     """Returns the path of this file on the local disk relative to client root. | 
| (...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1086         break | 1086         break | 
| 1087       parent_dir = os.path.dirname(directory) | 1087       parent_dir = os.path.dirname(directory) | 
| 1088       if parent_dir == directory: | 1088       if parent_dir == directory: | 
| 1089         # We hit the system root directory. | 1089         # We hit the system root directory. | 
| 1090         break | 1090         break | 
| 1091       directory = parent_dir | 1091       directory = parent_dir | 
| 1092 | 1092 | 
| 1093   # Look for PRESUBMIT.py in all candidate directories. | 1093   # Look for PRESUBMIT.py in all candidate directories. | 
| 1094   results = [] | 1094   results = [] | 
| 1095   for directory in sorted(list(candidates)): | 1095   for directory in sorted(list(candidates)): | 
| 1096     p = os.path.join(directory, 'PRESUBMIT.py') | 1096     for f in os.listdir(directory): | 
| 1097     if os.path.isfile(p): | 1097       p = os.path.join(directory, f) | 
| 1098       results.append(p) | 1098       if os.path.isfile(p) and re.match( | 
|  | 1099           r'PRESUBMIT.*\.py$', f) and not f.startswith('PRESUBMIT_test'): | 
|  | 1100         results.append(p) | 
| 1099 | 1101 | 
| 1100   logging.debug('Presubmit files: %s' % ','.join(results)) | 1102   logging.debug('Presubmit files: %s', ','.join(results)) | 
| 1101   return results | 1103   return results | 
| 1102 | 1104 | 
| 1103 | 1105 | 
| 1104 class GetTrySlavesExecuter(object): | 1106 class GetTrySlavesExecuter(object): | 
| 1105   @staticmethod | 1107   @staticmethod | 
| 1106   def ExecPresubmitScript(script_text, presubmit_path, project, change): | 1108   def ExecPresubmitScript(script_text, presubmit_path, project, change): | 
| 1107     """Executes GetPreferredTrySlaves() from a single presubmit script. | 1109     """Executes GetPreferredTrySlaves() from a single presubmit script. | 
| 1108 | 1110 | 
| 1109     This will soon be deprecated and replaced by GetPreferredTryMasters(). | 1111     This will soon be deprecated and replaced by GetPreferredTryMasters(). | 
| 1110 | 1112 | 
| (...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1447       raise PresubmitFailure('"%s" had an exception.\n%s' % (presubmit_path, e)) | 1449       raise PresubmitFailure('"%s" had an exception.\n%s' % (presubmit_path, e)) | 
| 1448 | 1450 | 
| 1449     # These function names must change if we make substantial changes to | 1451     # These function names must change if we make substantial changes to | 
| 1450     # the presubmit API that are not backwards compatible. | 1452     # the presubmit API that are not backwards compatible. | 
| 1451     if self.committing: | 1453     if self.committing: | 
| 1452       function_name = 'CheckChangeOnCommit' | 1454       function_name = 'CheckChangeOnCommit' | 
| 1453     else: | 1455     else: | 
| 1454       function_name = 'CheckChangeOnUpload' | 1456       function_name = 'CheckChangeOnUpload' | 
| 1455     if function_name in context: | 1457     if function_name in context: | 
| 1456       context['__args'] = (input_api, OutputApi(self.committing)) | 1458       context['__args'] = (input_api, OutputApi(self.committing)) | 
| 1457       logging.debug('Running %s in %s' % (function_name, presubmit_path)) | 1459       logging.debug('Running %s in %s', function_name, presubmit_path) | 
| 1458       result = eval(function_name + '(*__args)', context) | 1460       result = eval(function_name + '(*__args)', context) | 
| 1459       logging.debug('Running %s done.' % function_name) | 1461       logging.debug('Running %s done.', function_name) | 
| 1460       if not (isinstance(result, types.TupleType) or | 1462       if not (isinstance(result, types.TupleType) or | 
| 1461               isinstance(result, types.ListType)): | 1463               isinstance(result, types.ListType)): | 
| 1462         raise PresubmitFailure( | 1464         raise PresubmitFailure( | 
| 1463           'Presubmit functions must return a tuple or list') | 1465           'Presubmit functions must return a tuple or list') | 
| 1464       for item in result: | 1466       for item in result: | 
| 1465         if not isinstance(item, OutputApi.PresubmitResult): | 1467         if not isinstance(item, OutputApi.PresubmitResult): | 
| 1466           raise PresubmitFailure( | 1468           raise PresubmitFailure( | 
| 1467             'All presubmit results must be of types derived from ' | 1469             'All presubmit results must be of types derived from ' | 
| 1468             'output_api.PresubmitResult') | 1470             'output_api.PresubmitResult') | 
| 1469     else: | 1471     else: | 
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1602         dirs.remove('.svn') | 1604         dirs.remove('.svn') | 
| 1603       if '.git' in dirs: | 1605       if '.git' in dirs: | 
| 1604         dirs.remove('.git') | 1606         dirs.remove('.git') | 
| 1605       for name in files: | 1607       for name in files: | 
| 1606         if fnmatch.fnmatch(name, mask): | 1608         if fnmatch.fnmatch(name, mask): | 
| 1607           results.append(os.path.join(root, name)) | 1609           results.append(os.path.join(root, name)) | 
| 1608     return results | 1610     return results | 
| 1609 | 1611 | 
| 1610 | 1612 | 
| 1611 def ParseFiles(args, recursive): | 1613 def ParseFiles(args, recursive): | 
| 1612   logging.debug('Searching for %s' % args) | 1614   logging.debug('Searching for %s', args) | 
| 1613   files = [] | 1615   files = [] | 
| 1614   for arg in args: | 1616   for arg in args: | 
| 1615     files.extend([('M', f) for f in ScanSubDirs(arg, recursive)]) | 1617     files.extend([('M', f) for f in ScanSubDirs(arg, recursive)]) | 
| 1616   return files | 1618   return files | 
| 1617 | 1619 | 
| 1618 | 1620 | 
| 1619 def load_files(options, args): | 1621 def load_files(options, args): | 
| 1620   """Tries to determine the SCM.""" | 1622   """Tries to determine the SCM.""" | 
| 1621   change_scm = scm.determine_scm(options.root) | 1623   change_scm = scm.determine_scm(options.root) | 
| 1622   files = [] | 1624   files = [] | 
| 1623   if args: | 1625   if args: | 
| 1624     files = ParseFiles(args, options.recursive) | 1626     files = ParseFiles(args, options.recursive) | 
| 1625   if change_scm == 'svn': | 1627   if change_scm == 'svn': | 
| 1626     change_class = SvnChange | 1628     change_class = SvnChange | 
| 1627     if not files: | 1629     if not files: | 
| 1628       files = scm.SVN.CaptureStatus([], options.root) | 1630       files = scm.SVN.CaptureStatus([], options.root) | 
| 1629   elif change_scm == 'git': | 1631   elif change_scm == 'git': | 
| 1630     change_class = GitChange | 1632     change_class = GitChange | 
| 1631     upstream = options.upstream or None | 1633     upstream = options.upstream or None | 
| 1632     if not files: | 1634     if not files: | 
| 1633       files = scm.GIT.CaptureStatus([], options.root, upstream) | 1635       files = scm.GIT.CaptureStatus([], options.root, upstream) | 
| 1634   else: | 1636   else: | 
| 1635     logging.info('Doesn\'t seem under source control. Got %d files' % len(args)) | 1637     logging.info('Doesn\'t seem under source control. Got %d files', len(args)) | 
| 1636     if not files: | 1638     if not files: | 
| 1637       return None, None | 1639       return None, None | 
| 1638     change_class = Change | 1640     change_class = Change | 
| 1639   return change_class, files | 1641   return change_class, files | 
| 1640 | 1642 | 
| 1641 | 1643 | 
| 1642 class NonexistantCannedCheckFilter(Exception): | 1644 class NonexistantCannedCheckFilter(Exception): | 
| 1643   pass | 1645   pass | 
| 1644 | 1646 | 
| 1645 | 1647 | 
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1747   if options.rietveld_email and options.rietveld_email_file: | 1749   if options.rietveld_email and options.rietveld_email_file: | 
| 1748     parser.error("Only one of --rietveld_email or --rietveld_email_file " | 1750     parser.error("Only one of --rietveld_email or --rietveld_email_file " | 
| 1749                  "can be passed to this program.") | 1751                  "can be passed to this program.") | 
| 1750   if options.rietveld_email_file: | 1752   if options.rietveld_email_file: | 
| 1751     with open(options.rietveld_email_file, "rb") as f: | 1753     with open(options.rietveld_email_file, "rb") as f: | 
| 1752       options.rietveld_email = f.read().strip() | 1754       options.rietveld_email = f.read().strip() | 
| 1753 | 1755 | 
| 1754   change_class, files = load_files(options, args) | 1756   change_class, files = load_files(options, args) | 
| 1755   if not change_class: | 1757   if not change_class: | 
| 1756     parser.error('For unversioned directory, <files> is not optional.') | 1758     parser.error('For unversioned directory, <files> is not optional.') | 
| 1757   logging.info('Found %d file(s).' % len(files)) | 1759   logging.info('Found %d file(s).', len(files)) | 
| 1758 | 1760 | 
| 1759   rietveld_obj, gerrit_obj = None, None | 1761   rietveld_obj, gerrit_obj = None, None | 
| 1760 | 1762 | 
| 1761   if options.rietveld_url: | 1763   if options.rietveld_url: | 
| 1762     # The empty password is permitted: '' is not None. | 1764     # The empty password is permitted: '' is not None. | 
| 1763     if options.rietveld_private_key_file: | 1765     if options.rietveld_private_key_file: | 
| 1764       rietveld_obj = rietveld.JwtOAuth2Rietveld( | 1766       rietveld_obj = rietveld.JwtOAuth2Rietveld( | 
| 1765         options.rietveld_url, | 1767         options.rietveld_url, | 
| 1766         options.rietveld_email, | 1768         options.rietveld_email, | 
| 1767         options.rietveld_private_key_file) | 1769         options.rietveld_private_key_file) | 
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1820     return 2 | 1822     return 2 | 
| 1821 | 1823 | 
| 1822 | 1824 | 
| 1823 if __name__ == '__main__': | 1825 if __name__ == '__main__': | 
| 1824   fix_encoding.fix_encoding() | 1826   fix_encoding.fix_encoding() | 
| 1825   try: | 1827   try: | 
| 1826     sys.exit(main()) | 1828     sys.exit(main()) | 
| 1827   except KeyboardInterrupt: | 1829   except KeyboardInterrupt: | 
| 1828     sys.stderr.write('interrupted\n') | 1830     sys.stderr.write('interrupted\n') | 
| 1829     sys.exit(2) | 1831     sys.exit(2) | 
| OLD | NEW | 
|---|