OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # | 2 # |
3 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 3 # Copyright (c) 2013 The Chromium Authors. All rights reserved. |
4 # Use of this source code is governed by a BSD-style license that can be | 4 # Use of this source code is governed by a BSD-style license that can be |
5 # found in the LICENSE file. | 5 # found in the LICENSE file. |
6 | 6 |
7 import collections | 7 import collections |
8 import copy | 8 import copy |
9 import json | 9 import json |
10 import os | 10 import os |
11 import pipes | 11 import pipes |
12 import re | 12 import re |
13 import subprocess | 13 import subprocess |
14 import sys | 14 import sys |
15 | 15 |
16 import bb_utils | 16 import bb_utils |
17 | 17 |
18 BotConfig = collections.namedtuple( | 18 BotConfig = collections.namedtuple( |
Isaac (away)
2013/06/28 01:39:12
Rename these to start with _
Siva Chandra
2013/06/28 21:34:10
Done.
| |
19 'BotConfig', ['bot_id', 'host_obj', 'test_obj']) | 19 'BotConfig', ['bot_id', 'host_obj', 'test_obj']) |
20 | 20 |
21 HostConfig = collections.namedtuple( | 21 HostConfig = collections.namedtuple( |
22 'HostConfig', | 22 'HostConfig', |
23 ['host_steps', 'extra_args', 'extra_gyp_defines', 'target_arch']) | 23 ['host_steps', 'extra_args', 'extra_gyp_defines', 'target_arch']) |
24 | 24 |
25 TestConfig = collections.namedtuple('Tests', ['tests', 'extra_args']) | 25 TestConfig = collections.namedtuple('Tests', ['tests', 'extra_args']) |
26 | 26 |
27 | 27 |
28 def CreateBotConfig(bot_id, host_object, test_object=None): | |
Isaac (away)
2013/06/28 01:39:12
Just call these BotConfig, HostConfig and TestConf
Siva Chandra
2013/06/28 21:34:10
Done.
| |
29 return BotConfig(bot_id, host_object, test_object) | |
30 | |
31 def CreateTestConfig(tests, extra_args=None): | |
32 return TestConfig(tests, extra_args) | |
33 | |
34 def CreateHostConfig(host_steps, extra_args=None, extra_gyp=None, | |
35 target_arch=None): | |
36 return HostConfig(host_steps, extra_args, extra_gyp, target_arch) | |
37 | |
38 | |
28 def DictDiff(d1, d2): | 39 def DictDiff(d1, d2): |
29 diff = [] | 40 diff = [] |
30 for key in sorted(set(d1.keys() + d2.keys())): | 41 for key in sorted(set(d1.keys() + d2.keys())): |
31 if key in d1 and d1[key] != d2.get(key): | 42 if key in d1 and d1[key] != d2.get(key): |
32 diff.append('- %s=%s' % (key, pipes.quote(d1[key]))) | 43 diff.append('- %s=%s' % (key, pipes.quote(d1[key]))) |
33 if key in d2 and d2[key] != d1.get(key): | 44 if key in d2 and d2[key] != d1.get(key): |
34 diff.append('+ %s=%s' % (key, pipes.quote(d2[key]))) | 45 diff.append('+ %s=%s' % (key, pipes.quote(d2[key]))) |
35 return '\n'.join(diff) | 46 return '\n'.join(diff) |
36 | 47 |
37 | 48 |
(...skipping 29 matching lines...) Expand all Loading... | |
67 | 78 |
68 # Bots checkout chrome in /b/build/slave/<name>/build/src | 79 # Bots checkout chrome in /b/build/slave/<name>/build/src |
69 build_internal_android = os.path.abspath(os.path.join( | 80 build_internal_android = os.path.abspath(os.path.join( |
70 bb_utils.CHROME_SRC, '..', '..', '..', '..', '..', 'build_internal', | 81 bb_utils.CHROME_SRC, '..', '..', '..', '..', '..', 'build_internal', |
71 'scripts', 'slave', 'android')) | 82 'scripts', 'slave', 'android')) |
72 if os.path.exists(build_internal_android): | 83 if os.path.exists(build_internal_android): |
73 env['PATH'] = os.pathsep.join([build_internal_android, env['PATH']]) | 84 env['PATH'] = os.pathsep.join([build_internal_android, env['PATH']]) |
74 return env | 85 return env |
75 | 86 |
76 | 87 |
77 def GetCommands(options, bot_config): | 88 def GetCommands(options, bot_config, host_step_script, device_step_script): |
Isaac (away)
2013/06/28 01:39:12
These args are fragile, I'd prefer overrides to th
Siva Chandra
2013/06/28 21:34:10
Done.
| |
78 """Get a formatted list of commands. | 89 """Get a formatted list of commands. |
79 | 90 |
80 Args: | 91 Args: |
81 options: Options object. | 92 options: Options object. |
82 bot_config: A BotConfig named tuple. | 93 bot_config: A BotConfig named tuple. |
94 host_step_script: Host step script. | |
95 device_step_script: Device step script. | |
83 Returns: | 96 Returns: |
84 list of Command objects. | 97 list of Command objects. |
85 """ | 98 """ |
86 property_args = bb_utils.EncodeProperties(options) | 99 property_args = bb_utils.EncodeProperties(options) |
87 commands = [['build/android/buildbot/bb_host_steps.py'] + | 100 commands = [[host_step_script, |
88 ['--steps=%s' % ','.join(bot_config.host_obj.host_steps)] + | 101 '--steps=%s' % ','.join(bot_config.host_obj.host_steps)] + |
89 property_args + (bot_config.host_obj.extra_args or [])] | 102 property_args + (bot_config.host_obj.extra_args or [])] |
90 | 103 |
91 test_obj = bot_config.test_obj | 104 test_obj = bot_config.test_obj |
92 if test_obj: | 105 if test_obj: |
93 run_test_cmd = [ | 106 run_test_cmd = [device_step_script, '--reboot'] + property_args |
94 'build/android/buildbot/bb_device_steps.py', '--reboot'] + property_args | |
95 for test in test_obj.tests: | 107 for test in test_obj.tests: |
96 run_test_cmd.extend(['-f', test]) | 108 run_test_cmd.extend(['-f', test]) |
97 if test_obj.extra_args: | 109 if test_obj.extra_args: |
98 run_test_cmd.extend(test_obj.extra_args) | 110 run_test_cmd.extend(test_obj.extra_args) |
99 commands.append(run_test_cmd) | 111 commands.append(run_test_cmd) |
100 return commands | 112 return commands |
101 | 113 |
102 | 114 |
103 def GetBotStepMap(): | 115 def GetBotStepMap(): |
104 compile_step = ['compile'] | 116 compile_step = ['compile'] |
105 std_host_tests = ['check_webview_licenses', 'findbugs'] | 117 std_host_tests = ['check_webview_licenses', 'findbugs'] |
106 std_build_steps = ['compile', 'zip_build'] | 118 std_build_steps = ['compile', 'zip_build'] |
107 std_test_steps = ['extract_build'] | 119 std_test_steps = ['extract_build'] |
108 std_tests = ['ui', 'unit'] | 120 std_tests = ['ui', 'unit'] |
109 flakiness_server = '--upload-to-flakiness-server' | 121 flakiness_server = '--upload-to-flakiness-server' |
110 | 122 |
111 def B(bot_id, host_object, test_object=None): | 123 B = CreateBotConfig |
112 return BotConfig(bot_id, host_object, test_object) | 124 H = CreateHostConfig |
113 | 125 T = CreateTestConfig |
114 def T(tests, extra_args=None): | |
115 return TestConfig(tests, extra_args) | |
116 | |
117 def H(host_steps, extra_args=None, extra_gyp=None, target_arch=None): | |
118 return HostConfig(host_steps, extra_args, extra_gyp, target_arch) | |
119 | 126 |
120 bot_configs = [ | 127 bot_configs = [ |
121 # Main builders | 128 # Main builders |
122 B('main-builder-dbg', H(std_build_steps + std_host_tests)), | 129 B('main-builder-dbg', H(std_build_steps + std_host_tests)), |
123 B('main-builder-rel', H(std_build_steps)), | 130 B('main-builder-rel', H(std_build_steps)), |
124 B('main-clang-builder', | 131 B('main-clang-builder', |
125 H(compile_step, extra_gyp='clang=1 component=shared_library')), | 132 H(compile_step, extra_gyp='clang=1 component=shared_library')), |
126 B('main-clobber', H(compile_step)), | 133 B('main-clobber', H(compile_step)), |
127 B('main-tests', H(std_test_steps), T(std_tests, [flakiness_server])), | 134 B('main-tests', H(std_test_steps), T(std_tests, [flakiness_server])), |
128 | 135 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
173 # Trybots do not upload to flakiness dashboard. They should be otherwise | 180 # Trybots do not upload to flakiness dashboard. They should be otherwise |
174 # identical in configuration to their trunk building counterparts. | 181 # identical in configuration to their trunk building counterparts. |
175 test_obj = bot_map[to_id].test_obj | 182 test_obj = bot_map[to_id].test_obj |
176 if to_id.startswith('try') and test_obj: | 183 if to_id.startswith('try') and test_obj: |
177 extra_args = test_obj.extra_args | 184 extra_args = test_obj.extra_args |
178 if extra_args and flakiness_server in extra_args: | 185 if extra_args and flakiness_server in extra_args: |
179 extra_args.remove(flakiness_server) | 186 extra_args.remove(flakiness_server) |
180 return bot_map | 187 return bot_map |
181 | 188 |
182 | 189 |
183 def main(argv): | 190 def GetBotConfig(bot_step_map, bot_id): |
Isaac (away)
2013/06/28 01:39:12
Please name this something more generic, such as '
Siva Chandra
2013/06/28 21:34:10
Done.
| |
191 bot_config = bot_step_map.get(bot_id) | |
192 if not bot_config: | |
193 substring_matches = filter(lambda x: x in bot_id, bot_step_map.iterkeys()) | |
194 if substring_matches: | |
195 max_id = max(substring_matches, key=len) | |
196 print 'Using config from id="%s" (substring match).' % max_id | |
197 bot_config = bot_step_map[max_id] | |
198 return bot_config | |
199 | |
200 | |
201 def GetRunBotOptParser(): | |
184 parser = bb_utils.GetParser() | 202 parser = bb_utils.GetParser() |
185 parser.add_option('--bot-id', help='Specify bot id directly.') | 203 parser.add_option('--bot-id', help='Specify bot id directly.') |
186 parser.add_option('--testing', action='store_true', | 204 parser.add_option('--testing', action='store_true', |
187 help='For testing: print, but do not run commands') | 205 help='For testing: print, but do not run commands') |
206 | |
207 return parser | |
208 | |
209 | |
210 def main(argv): | |
211 parser = GetRunBotOptParser() | |
188 options, args = parser.parse_args(argv[1:]) | 212 options, args = parser.parse_args(argv[1:]) |
189 if args: | 213 if args: |
190 parser.error('Unused args: %s' % args) | 214 parser.error('Unused args: %s' % args) |
191 | 215 |
192 bot_id = options.bot_id or options.factory_properties.get('android_bot_id') | 216 bot_id = options.bot_id or options.factory_properties.get('android_bot_id') |
193 if not bot_id: | 217 if not bot_id: |
194 parser.error('A bot id must be specified through option or factory_props.') | 218 parser.error('A bot id must be specified through option or factory_props.') |
195 | 219 |
196 # Get a BotConfig object looking first for an exact bot-id match. If no exact | 220 # Get a BotConfig object looking first for an exact bot-id match. If no exact |
197 # match, look for a bot-id which is a substring of the specified id. | 221 # match, look for a bot-id which is a substring of the specified id. |
198 # This allows similar bots to have unique IDs, but to share config. | 222 # This allows similar bots to have unique IDs, but to share config. |
199 # If multiple substring matches exist, pick the longest one. | 223 # If multiple substring matches exist, pick the longest one. |
200 bot_map = GetBotStepMap() | 224 bot_config = GetBotConfig(GetBotStepMap(), bot_id) |
201 bot_config = bot_map.get(bot_id) | |
202 if not bot_config: | |
203 substring_matches = filter(lambda x: x in bot_id, bot_map.iterkeys()) | |
204 if substring_matches: | |
205 max_id = max(substring_matches, key=len) | |
206 print 'Using config from id="%s" (substring match).' % max_id | |
207 bot_config = bot_map[max_id] | |
208 if not bot_config: | 225 if not bot_config: |
209 print 'Error: config for id="%s" cannot be inferred.' % bot_id | 226 print 'Error: config for id="%s" cannot be inferred.' % bot_id |
210 return 1 | 227 return 1 |
211 | 228 |
212 print 'Using config:', bot_config | 229 print 'Using config:', bot_config |
213 | 230 |
214 commands = GetCommands(options, bot_config) | 231 commands = GetCommands( |
232 options, bot_config, | |
233 'build/android/buildbot/bb_host_steps.py', | |
234 'build/android/buildbot/bb_device_steps.py') | |
215 for command in commands: | 235 for command in commands: |
216 print 'Will run: ', bb_utils.CommandToString(command) | 236 print 'Will run: ', bb_utils.CommandToString(command) |
217 print | 237 print |
218 | 238 |
219 env = GetEnvironment(bot_config.host_obj, options.testing) | 239 env = GetEnvironment(bot_config.host_obj, options.testing) |
220 print 'Environment changes:' | 240 print 'Environment changes:' |
221 print DictDiff(dict(os.environ), env) | 241 print DictDiff(dict(os.environ), env) |
222 | 242 |
223 for command in commands: | 243 for command in commands: |
224 print bb_utils.CommandToString(command) | 244 print bb_utils.CommandToString(command) |
225 sys.stdout.flush() | 245 sys.stdout.flush() |
226 if options.testing: | 246 if options.testing: |
227 env['BUILDBOT_TESTING'] = '1' | 247 env['BUILDBOT_TESTING'] = '1' |
228 return_code = subprocess.call(command, cwd=bb_utils.CHROME_SRC, env=env) | 248 return_code = subprocess.call(command, cwd=bb_utils.CHROME_SRC, env=env) |
229 if return_code != 0: | 249 if return_code != 0: |
230 return return_code | 250 return return_code |
231 | 251 |
232 | 252 |
233 if __name__ == '__main__': | 253 if __name__ == '__main__': |
234 sys.exit(main(sys.argv)) | 254 sys.exit(main(sys.argv)) |
OLD | NEW |