| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2011 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.6.1' | 9 __version__ = '1.6.1' |
| 10 | 10 |
| 11 # TODO(joi) Add caching where appropriate/needed. The API is designed to allow | 11 # TODO(joi) Add caching where appropriate/needed. The API is designed to allow |
| 12 # caching (between all different invocations of presubmit scripts for a given | 12 # caching (between all different invocations of presubmit scripts for a given |
| 13 # change). We should add it as our presubmit scripts start feeling slow. | 13 # change). We should add it as our presubmit scripts start feeling slow. |
| 14 | 14 |
| 15 import cPickle # Exposed through the API. | 15 import cPickle # Exposed through the API. |
| 16 import cStringIO # Exposed through the API. | 16 import cStringIO # Exposed through the API. |
| 17 import fnmatch | 17 import fnmatch |
| 18 import glob | 18 import glob |
| 19 import inspect |
| 19 import logging | 20 import logging |
| 20 import marshal # Exposed through the API. | 21 import marshal # Exposed through the API. |
| 21 import optparse | 22 import optparse |
| 22 import os # Somewhat exposed through the API. | 23 import os # Somewhat exposed through the API. |
| 23 import pickle # Exposed through the API. | 24 import pickle # Exposed through the API. |
| 24 import random | 25 import random |
| 25 import re # Exposed through the API. | 26 import re # Exposed through the API. |
| 26 import sys # Parts exposed through API. | 27 import sys # Parts exposed through API. |
| 27 import tempfile # Exposed through the API. | 28 import tempfile # Exposed through the API. |
| 28 import time | 29 import time |
| (...skipping 839 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 868 p = os.path.join(directory, 'PRESUBMIT.py') | 869 p = os.path.join(directory, 'PRESUBMIT.py') |
| 869 if os.path.isfile(p): | 870 if os.path.isfile(p): |
| 870 results.append(p) | 871 results.append(p) |
| 871 | 872 |
| 872 logging.debug('Presubmit files: %s' % ','.join(results)) | 873 logging.debug('Presubmit files: %s' % ','.join(results)) |
| 873 return results | 874 return results |
| 874 | 875 |
| 875 | 876 |
| 876 class GetTrySlavesExecuter(object): | 877 class GetTrySlavesExecuter(object): |
| 877 @staticmethod | 878 @staticmethod |
| 878 def ExecPresubmitScript(script_text, presubmit_path, project): | 879 def ExecPresubmitScript(script_text, presubmit_path, project, change): |
| 879 """Executes GetPreferredTrySlaves() from a single presubmit script. | 880 """Executes GetPreferredTrySlaves() from a single presubmit script. |
| 880 | 881 |
| 881 Args: | 882 Args: |
| 882 script_text: The text of the presubmit script. | 883 script_text: The text of the presubmit script. |
| 883 presubmit_path: Project script to run. | 884 presubmit_path: Project script to run. |
| 884 project: Project name to pass to presubmit script for bot selection. | 885 project: Project name to pass to presubmit script for bot selection. |
| 885 | 886 |
| 886 Return: | 887 Return: |
| 887 A list of try slaves. | 888 A list of try slaves. |
| 888 """ | 889 """ |
| 889 context = {} | 890 context = {} |
| 890 try: | 891 try: |
| 891 exec script_text in context | 892 exec script_text in context |
| 892 except Exception, e: | 893 except Exception, e: |
| 893 raise PresubmitFailure('"%s" had an exception.\n%s' % (presubmit_path, e)) | 894 raise PresubmitFailure('"%s" had an exception.\n%s' % (presubmit_path, e)) |
| 894 | 895 |
| 895 function_name = 'GetPreferredTrySlaves' | 896 function_name = 'GetPreferredTrySlaves' |
| 896 if function_name in context: | 897 if function_name in context: |
| 897 try: | 898 get_preferred_try_slaves = context[function_name] |
| 898 result = eval(function_name + '(' + repr(project) + ')', context) | 899 function_info = inspect.getargspec(get_preferred_try_slaves) |
| 899 except TypeError: | 900 if len(function_info[0]) == 1: |
| 900 result = eval(function_name + '()', context) | 901 result = get_preferred_try_slaves(project) |
| 902 elif len(function_info[0]) == 2: |
| 903 result = get_preferred_try_slaves(project, change) |
| 904 else: |
| 905 result = get_preferred_try_slaves() |
| 901 if not isinstance(result, types.ListType): | 906 if not isinstance(result, types.ListType): |
| 902 raise PresubmitFailure( | 907 raise PresubmitFailure( |
| 903 'Presubmit functions must return a list, got a %s instead: %s' % | 908 'Presubmit functions must return a list, got a %s instead: %s' % |
| 904 (type(result), str(result))) | 909 (type(result), str(result))) |
| 905 for item in result: | 910 for item in result: |
| 906 if not isinstance(item, basestring): | 911 if not isinstance(item, basestring): |
| 907 raise PresubmitFailure('All try slaves names must be strings.') | 912 raise PresubmitFailure('All try slaves names must be strings.') |
| 908 if item != item.strip(): | 913 if item != item.strip(): |
| 909 raise PresubmitFailure( | 914 raise PresubmitFailure( |
| 910 'Try slave names cannot start/end with whitespace') | 915 'Try slave names cannot start/end with whitespace') |
| 911 else: | 916 else: |
| 912 result = [] | 917 result = [] |
| 913 return result | 918 return result |
| 914 | 919 |
| 915 | 920 |
| 916 def DoGetTrySlaves(changed_files, | 921 def DoGetTrySlaves(change, |
| 922 changed_files, |
| 917 repository_root, | 923 repository_root, |
| 918 default_presubmit, | 924 default_presubmit, |
| 919 project, | 925 project, |
| 920 verbose, | 926 verbose, |
| 921 output_stream): | 927 output_stream): |
| 922 """Get the list of try servers from the presubmit scripts. | 928 """Get the list of try servers from the presubmit scripts. |
| 923 | 929 |
| 924 Args: | 930 Args: |
| 925 changed_files: List of modified files. | 931 changed_files: List of modified files. |
| 926 repository_root: The repository root. | 932 repository_root: The repository root. |
| 927 default_presubmit: A default presubmit script to execute in any case. | 933 default_presubmit: A default presubmit script to execute in any case. |
| 928 project: Optional name of a project used in selecting trybots. | 934 project: Optional name of a project used in selecting trybots. |
| 929 verbose: Prints debug info. | 935 verbose: Prints debug info. |
| 930 output_stream: A stream to write debug output to. | 936 output_stream: A stream to write debug output to. |
| 931 | 937 |
| 932 Return: | 938 Return: |
| 933 List of try slaves | 939 List of try slaves |
| 934 """ | 940 """ |
| 935 presubmit_files = ListRelevantPresubmitFiles(changed_files, repository_root) | 941 presubmit_files = ListRelevantPresubmitFiles(changed_files, repository_root) |
| 936 if not presubmit_files and verbose: | 942 if not presubmit_files and verbose: |
| 937 output_stream.write("Warning, no presubmit.py found.\n") | 943 output_stream.write("Warning, no presubmit.py found.\n") |
| 938 results = [] | 944 results = [] |
| 939 executer = GetTrySlavesExecuter() | 945 executer = GetTrySlavesExecuter() |
| 940 if default_presubmit: | 946 if default_presubmit: |
| 941 if verbose: | 947 if verbose: |
| 942 output_stream.write("Running default presubmit script.\n") | 948 output_stream.write("Running default presubmit script.\n") |
| 943 fake_path = os.path.join(repository_root, 'PRESUBMIT.py') | 949 fake_path = os.path.join(repository_root, 'PRESUBMIT.py') |
| 944 results += executer.ExecPresubmitScript( | 950 results += executer.ExecPresubmitScript( |
| 945 default_presubmit, fake_path, project) | 951 default_presubmit, fake_path, project, change) |
| 946 for filename in presubmit_files: | 952 for filename in presubmit_files: |
| 947 filename = os.path.abspath(filename) | 953 filename = os.path.abspath(filename) |
| 948 if verbose: | 954 if verbose: |
| 949 output_stream.write("Running %s\n" % filename) | 955 output_stream.write("Running %s\n" % filename) |
| 950 # Accept CRLF presubmit script. | 956 # Accept CRLF presubmit script. |
| 951 presubmit_script = gclient_utils.FileRead(filename, 'rU') | 957 presubmit_script = gclient_utils.FileRead(filename, 'rU') |
| 952 results += executer.ExecPresubmitScript( | 958 results += executer.ExecPresubmitScript( |
| 953 presubmit_script, filename, project) | 959 presubmit_script, filename, project, change) |
| 954 | 960 |
| 955 slaves = list(set(results)) | 961 slaves = list(set(results)) |
| 956 if slaves and verbose: | 962 if slaves and verbose: |
| 957 output_stream.write(', '.join(slaves)) | 963 output_stream.write(', '.join(slaves)) |
| 958 output_stream.write('\n') | 964 output_stream.write('\n') |
| 959 return slaves | 965 return slaves |
| 960 | 966 |
| 961 | 967 |
| 962 class PresubmitExecuter(object): | 968 class PresubmitExecuter(object): |
| 963 def __init__(self, change, committing, rietveld_obj, verbose): | 969 def __init__(self, change, committing, rietveld_obj, verbose): |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1246 except PresubmitFailure, e: | 1252 except PresubmitFailure, e: |
| 1247 print >> sys.stderr, e | 1253 print >> sys.stderr, e |
| 1248 print >> sys.stderr, 'Maybe your depot_tools is out of date?' | 1254 print >> sys.stderr, 'Maybe your depot_tools is out of date?' |
| 1249 print >> sys.stderr, 'If all fails, contact maruel@' | 1255 print >> sys.stderr, 'If all fails, contact maruel@' |
| 1250 return 2 | 1256 return 2 |
| 1251 | 1257 |
| 1252 | 1258 |
| 1253 if __name__ == '__main__': | 1259 if __name__ == '__main__': |
| 1254 fix_encoding.fix_encoding() | 1260 fix_encoding.fix_encoding() |
| 1255 sys.exit(Main(None)) | 1261 sys.exit(Main(None)) |
| OLD | NEW |