OLD | NEW |
---|---|
(Empty) | |
1 #!/usr/bin/python | |
2 | |
3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | |
4 # Use of this source code is governed by a BSD-style license that can be | |
5 # found in the LICENSE file. | |
6 | |
7 """ | |
8 Shared code for use in the buildbot scripts. | |
9 """ | |
10 | |
11 import optparse | |
12 import os | |
13 from os.path import abspath | |
14 from os.path import dirname | |
15 import subprocess | |
16 import sys | |
17 | |
18 DART_PATH = dirname(dirname(dirname(abspath(__file__)))) | |
19 | |
20 NO_COLOR_ENV = dict(os.environ) | |
21 NO_COLOR_ENV['TERM'] = 'nocolor' | |
22 | |
23 BUILDER_NAME = 'BUILDBOT_BUILDERNAME' | |
24 BUILDER_CLOBBER = 'BUILDBOT_CLOBBER' | |
25 | |
26 | |
27 class BuildInfo(object): | |
28 """ | |
29 Encapsulation of build information. | |
30 | |
31 - compiler: 'dart2js' or None when the builder has an incorrect name | |
Emily Fortuna
2012/10/23 23:09:49
Some of these comments should be updated if this i
Bob Nystrom
2012/10/24 00:46:44
Good catch. Done.
| |
32 - runtime: 'd8', 'ie', 'ff', 'safari', 'chrome', 'opera' | |
33 - mode: 'debug' or 'release' | |
34 - system: 'linux', 'mac', or 'win7' | |
35 - checked: True if we should run in checked mode, otherwise False | |
36 - host_checked: True if we should run in host checked mode, otherwise False | |
37 - shard_index: The shard we are running, None when not specified. | |
38 - total_shards: The total number of shards, None when not specified. | |
39 - is_buildbot: True if we are on a buildbot (or emulating it). | |
40 - test_set: Specification of a non standard test set, default None | |
41 """ | |
42 def __init__(self, compiler, runtime, mode, system, checked=False, | |
43 host_checked=False, shard_index=None, total_shards=None, | |
44 is_buildbot=False, test_set=None): | |
45 self.compiler = compiler | |
46 self.runtime = runtime | |
47 self.mode = mode | |
48 self.system = system | |
49 self.checked = checked | |
50 self.host_checked = host_checked | |
51 self.shard_index = shard_index | |
52 self.total_shards = total_shards | |
53 self.is_buildbot = is_buildbot | |
54 self.test_set = test_set | |
55 | |
56 def PrintBuildInfo(self): | |
57 shard_description = "" | |
58 if self.shard_index: | |
59 shard_description = " shard %s of %s" % (self.shard_index, | |
60 self.total_shards) | |
61 print ("compiler: %s, runtime: %s mode: %s, system: %s," | |
62 " checked: %s, host-checked: %s, test-set: %s%s" | |
63 ) % (self.compiler, self.runtime, self.mode, self.system, | |
64 self.checked, self.host_checked, self.test_set, | |
65 shard_description) | |
66 | |
67 | |
68 class BuildStep(object): | |
69 """ | |
70 A context manager for handling build steps. | |
71 | |
72 When the context manager is entered, it prints the "@@@BUILD_STEP __@@@" | |
73 message. If it exits from an error being raised it displays the | |
74 "@@@STEP_FAILURE@@@" message. | |
75 """ | |
76 def __init__(self, name): | |
77 self.name = name | |
78 | |
79 def __enter__(self): | |
80 print '@@@BUILD_STEP %s@@@' % self.name | |
81 | |
82 def __exit__(self, type, value, traceback): | |
83 if value: | |
84 print '@@@STEP_FAILURE@@@' | |
85 | |
86 | |
87 def RunBot(parse_name, custom_steps): | |
88 """ | |
89 The main function for running a buildbot. | |
90 | |
91 A buildbot script should invoke this once. The parse_name function will be | |
92 called with the name of the buildbot and should return an instance of | |
93 BuildInfo. This function will then set up the bot, build the SDK etc. When | |
94 that's done, it will call custom_steps, passing in the BuildInfo object. | |
95 | |
96 In that, you can perform any bot-specific build steps. | |
97 | |
98 This function will not return. It will call sys.exit() with an appropriate | |
99 exit code. | |
100 """ | |
101 if len(sys.argv) == 0: | |
102 print 'Script pathname not known, giving up.' | |
103 sys.exit(1) | |
104 | |
105 name = GetBotName() | |
106 build_info = parse_name(name) | |
107 if not build_info: | |
108 print 'Could not handle unfamiliar bot name "%s".' % name | |
109 sys.exit(1) | |
110 | |
111 # Make sure we are in the dart directory | |
112 os.chdir(DART_PATH) | |
113 | |
114 try: | |
115 Clobber(build_info.mode) | |
116 BuildSDK(build_info.mode, build_info.system) | |
117 | |
118 custom_steps(build_info) | |
119 except OSError as e: | |
120 sys.exit(e.errno) | |
121 | |
122 sys.exit(0) | |
123 | |
124 | |
125 def GetBotName(): | |
126 """ | |
127 Gets the name of the current buildbot. | |
128 """ | |
129 # For testing the bot locally, allow the user to pass in a buildbot name. | |
130 parser = optparse.OptionParser() | |
131 parser.add_option('-n', '--name', dest='name', help='The name of the build' | |
132 'bot you would like to emulate (ex: vm-mac-debug)', default=None) | |
133 args, _ = parser.parse_args() | |
134 | |
135 if args.name: | |
136 return args.name | |
137 | |
138 name = os.environ.get(BUILDER_NAME) | |
139 if not name: | |
140 print 'Use -n $BUILDBOT_NAME for the bot you would like to emulate.' | |
141 sys.exit(1) | |
142 | |
143 return name | |
144 | |
145 | |
146 def Clobber(mode): | |
147 """ | |
148 Clobbers the builder before we do the build, if appropriate. | |
149 | |
150 - mode: either 'debug' or 'release' | |
151 """ | |
152 if os.environ.get(BUILDER_CLOBBER) != "1": | |
153 return | |
154 | |
155 with BuildStep('Clobber'): | |
156 cmd = [sys.executable, | |
157 './tools/clean_output_directory.py', | |
158 '--mode=' + mode] | |
159 print 'Clobbering %s' % (' '.join(cmd)) | |
160 RunProcess(cmd) | |
161 | |
162 | |
163 def BuildSDK(mode, system): | |
164 """ | |
165 Builds the SDK. | |
166 | |
167 - mode: either 'debug' or 'release' | |
168 - system: either 'linux', 'mac', or 'win7' | |
169 """ | |
170 with BuildStep('Build SDK'): | |
171 args = [sys.executable, './tools/build.py', '--mode=' + mode, 'create_sdk'] | |
172 print 'Building SDK: %s' % (' '.join(args)) | |
173 RunProcess(args) | |
174 | |
175 | |
176 def RunTest(name, build_info, targets, flags=None): | |
177 """ | |
178 Runs test.py with the given settings. | |
179 """ | |
180 if not flags: | |
181 flags = [] | |
182 | |
183 step_name = GetStepName(name, flags) | |
184 with BuildStep(step_name): | |
185 sys.stdout.flush() | |
186 | |
187 cmd = [ | |
188 sys.executable, os.path.join(os.curdir, 'tools', 'test.py'), | |
189 '--step_name=' + step_name, | |
190 '--mode=' + build_info.mode, | |
191 '--compiler=' + build_info.compiler, | |
192 '--runtime=' + build_info.runtime, | |
193 '--progress=buildbot', | |
194 '-v', '--time', '--use-sdk', '--report' | |
195 ] | |
196 | |
197 if build_info.checked: | |
198 cmd.append('--checked') | |
199 | |
200 cmd.extend(flags) | |
201 cmd.extend(targets) | |
202 | |
203 print 'Running: %s' % (' '.join(cmd)) | |
204 RunProcess(cmd) | |
205 | |
206 | |
207 def RunProcess(command): | |
208 """ | |
209 Runs command. | |
210 | |
211 If a non-zero exit code is returned, raises an OSError with errno as the exit | |
212 code. | |
213 """ | |
214 exit_code = subprocess.call(command, env=NO_COLOR_ENV) | |
215 if exit_code != 0: | |
216 raise OSError(exit_code) | |
217 | |
218 | |
219 def GetStepName(name, flags): | |
220 """ | |
221 Filters out flags with '=' as this breaks the /stats feature of the buildbot. | |
222 """ | |
223 flags = [x for x in flags if not '=' in x] | |
224 return ('%s tests %s' % (name, ' '.join(flags))).strip() | |
OLD | NEW |