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 1066 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1077 if os.path.isfile(p) and re.match( | 1077 if os.path.isfile(p) and re.match( |
1078 r'PRESUBMIT.*\.py$', f) and not f.startswith('PRESUBMIT_test'): | 1078 r'PRESUBMIT.*\.py$', f) and not f.startswith('PRESUBMIT_test'): |
1079 results.append(p) | 1079 results.append(p) |
1080 except OSError: | 1080 except OSError: |
1081 pass | 1081 pass |
1082 | 1082 |
1083 logging.debug('Presubmit files: %s', ','.join(results)) | 1083 logging.debug('Presubmit files: %s', ','.join(results)) |
1084 return results | 1084 return results |
1085 | 1085 |
1086 | 1086 |
1087 class GetTrySlavesExecuter(object): | |
1088 @staticmethod | |
1089 def ExecPresubmitScript(script_text, presubmit_path, project, change): | |
1090 """Executes GetPreferredTrySlaves() from a single presubmit script. | |
1091 | |
1092 This will soon be deprecated and replaced by GetPreferredTryMasters(). | |
1093 | |
1094 Args: | |
1095 script_text: The text of the presubmit script. | |
1096 presubmit_path: Project script to run. | |
1097 project: Project name to pass to presubmit script for bot selection. | |
1098 | |
1099 Return: | |
1100 A list of try slaves. | |
1101 """ | |
1102 context = {} | |
1103 main_path = os.getcwd() | |
1104 try: | |
1105 os.chdir(os.path.dirname(presubmit_path)) | |
1106 exec script_text in context | |
1107 except Exception, e: | |
1108 raise PresubmitFailure('"%s" had an exception.\n%s' % (presubmit_path, e)) | |
1109 finally: | |
1110 os.chdir(main_path) | |
1111 | |
1112 function_name = 'GetPreferredTrySlaves' | |
1113 if function_name in context: | |
1114 get_preferred_try_slaves = context[function_name] | |
1115 function_info = inspect.getargspec(get_preferred_try_slaves) | |
1116 if len(function_info[0]) == 1: | |
1117 result = get_preferred_try_slaves(project) | |
1118 elif len(function_info[0]) == 2: | |
1119 result = get_preferred_try_slaves(project, change) | |
1120 else: | |
1121 result = get_preferred_try_slaves() | |
1122 if not isinstance(result, types.ListType): | |
1123 raise PresubmitFailure( | |
1124 'Presubmit functions must return a list, got a %s instead: %s' % | |
1125 (type(result), str(result))) | |
1126 for item in result: | |
1127 if isinstance(item, basestring): | |
1128 # Old-style ['bot'] format. | |
1129 botname = item | |
1130 elif isinstance(item, tuple): | |
1131 # New-style [('bot', set(['tests']))] format. | |
1132 botname = item[0] | |
1133 else: | |
1134 raise PresubmitFailure('PRESUBMIT.py returned invalid tryslave/test' | |
1135 ' format.') | |
1136 | |
1137 if botname != botname.strip(): | |
1138 raise PresubmitFailure( | |
1139 'Try slave names cannot start/end with whitespace') | |
1140 if ',' in botname: | |
1141 raise PresubmitFailure( | |
1142 'Do not use \',\' separated builder or test names: %s' % botname) | |
1143 else: | |
1144 result = [] | |
1145 | |
1146 def valid_oldstyle(result): | |
1147 return all(isinstance(i, basestring) for i in result) | |
1148 | |
1149 def valid_newstyle(result): | |
1150 return (all(isinstance(i, tuple) for i in result) and | |
1151 all(len(i) == 2 for i in result) and | |
1152 all(isinstance(i[0], basestring) for i in result) and | |
1153 all(isinstance(i[1], set) for i in result) | |
1154 ) | |
1155 | |
1156 # Ensure it's either all old-style or all new-style. | |
1157 if not valid_oldstyle(result) and not valid_newstyle(result): | |
1158 raise PresubmitFailure( | |
1159 'PRESUBMIT.py returned invalid trybot specification!') | |
1160 | |
1161 return result | |
1162 | |
1163 | |
1164 class GetTryMastersExecuter(object): | 1087 class GetTryMastersExecuter(object): |
1165 @staticmethod | 1088 @staticmethod |
1166 def ExecPresubmitScript(script_text, presubmit_path, project, change): | 1089 def ExecPresubmitScript(script_text, presubmit_path, project, change): |
1167 """Executes GetPreferredTryMasters() from a single presubmit script. | 1090 """Executes GetPreferredTryMasters() from a single presubmit script. |
1168 | 1091 |
1169 Args: | 1092 Args: |
1170 script_text: The text of the presubmit script. | 1093 script_text: The text of the presubmit script. |
1171 presubmit_path: Project script to run. | 1094 presubmit_path: Project script to run. |
1172 project: Project name to pass to presubmit script for bot selection. | 1095 project: Project name to pass to presubmit script for bot selection. |
1173 | 1096 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1215 function_name = 'PostUploadHook' | 1138 function_name = 'PostUploadHook' |
1216 if function_name not in context: | 1139 if function_name not in context: |
1217 return {} | 1140 return {} |
1218 post_upload_hook = context[function_name] | 1141 post_upload_hook = context[function_name] |
1219 if not len(inspect.getargspec(post_upload_hook)[0]) == 3: | 1142 if not len(inspect.getargspec(post_upload_hook)[0]) == 3: |
1220 raise PresubmitFailure( | 1143 raise PresubmitFailure( |
1221 'Expected function "PostUploadHook" to take three arguments.') | 1144 'Expected function "PostUploadHook" to take three arguments.') |
1222 return post_upload_hook(cl, change, OutputApi(False)) | 1145 return post_upload_hook(cl, change, OutputApi(False)) |
1223 | 1146 |
1224 | 1147 |
1225 def DoGetTrySlaves(change, | |
1226 changed_files, | |
1227 repository_root, | |
1228 default_presubmit, | |
1229 project, | |
1230 verbose, | |
1231 output_stream): | |
1232 """Get the list of try servers from the presubmit scripts (deprecated). | |
1233 | |
1234 Args: | |
1235 changed_files: List of modified files. | |
1236 repository_root: The repository root. | |
1237 default_presubmit: A default presubmit script to execute in any case. | |
1238 project: Optional name of a project used in selecting trybots. | |
1239 verbose: Prints debug info. | |
1240 output_stream: A stream to write debug output to. | |
1241 | |
1242 Return: | |
1243 List of try slaves | |
1244 """ | |
1245 presubmit_files = ListRelevantPresubmitFiles(changed_files, repository_root) | |
1246 if not presubmit_files and verbose: | |
1247 output_stream.write("Warning, no PRESUBMIT.py found.\n") | |
1248 results = [] | |
1249 executer = GetTrySlavesExecuter() | |
1250 | |
1251 if default_presubmit: | |
1252 if verbose: | |
1253 output_stream.write("Running default presubmit script.\n") | |
1254 fake_path = os.path.join(repository_root, 'PRESUBMIT.py') | |
1255 results.extend(executer.ExecPresubmitScript( | |
1256 default_presubmit, fake_path, project, change)) | |
1257 for filename in presubmit_files: | |
1258 filename = os.path.abspath(filename) | |
1259 if verbose: | |
1260 output_stream.write("Running %s\n" % filename) | |
1261 # Accept CRLF presubmit script. | |
1262 presubmit_script = gclient_utils.FileRead(filename, 'rU') | |
1263 results.extend(executer.ExecPresubmitScript( | |
1264 presubmit_script, filename, project, change)) | |
1265 | |
1266 | |
1267 slave_dict = {} | |
1268 old_style = filter(lambda x: isinstance(x, basestring), results) | |
1269 new_style = filter(lambda x: isinstance(x, tuple), results) | |
1270 | |
1271 for result in new_style: | |
1272 slave_dict.setdefault(result[0], set()).update(result[1]) | |
1273 slaves = list(slave_dict.items()) | |
1274 | |
1275 slaves.extend(set(old_style)) | |
1276 | |
1277 if slaves and verbose: | |
1278 output_stream.write(', '.join((str(x) for x in slaves))) | |
1279 output_stream.write('\n') | |
1280 return slaves | |
1281 | |
1282 | |
1283 def _MergeMasters(masters1, masters2): | 1148 def _MergeMasters(masters1, masters2): |
1284 """Merges two master maps. Merges also the tests of each builder.""" | 1149 """Merges two master maps. Merges also the tests of each builder.""" |
1285 result = {} | 1150 result = {} |
1286 for (master, builders) in itertools.chain(masters1.iteritems(), | 1151 for (master, builders) in itertools.chain(masters1.iteritems(), |
1287 masters2.iteritems()): | 1152 masters2.iteritems()): |
1288 new_builders = result.setdefault(master, {}) | 1153 new_builders = result.setdefault(master, {}) |
1289 for (builder, tests) in builders.iteritems(): | 1154 for (builder, tests) in builders.iteritems(): |
1290 new_builders.setdefault(builder, set([])).update(tests) | 1155 new_builders.setdefault(builder, set([])).update(tests) |
1291 return result | 1156 return result |
1292 | 1157 |
(...skipping 512 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1805 return 2 | 1670 return 2 |
1806 | 1671 |
1807 | 1672 |
1808 if __name__ == '__main__': | 1673 if __name__ == '__main__': |
1809 fix_encoding.fix_encoding() | 1674 fix_encoding.fix_encoding() |
1810 try: | 1675 try: |
1811 sys.exit(main()) | 1676 sys.exit(main()) |
1812 except KeyboardInterrupt: | 1677 except KeyboardInterrupt: |
1813 sys.stderr.write('interrupted\n') | 1678 sys.stderr.write('interrupted\n') |
1814 sys.exit(2) | 1679 sys.exit(2) |
OLD | NEW |