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: None, 'dart2dart', 'dart2js' or 'dartc'. |
| 32 - runtime: 'd8', 'ie', 'ff', 'safari', 'chrome', 'opera', or None. |
| 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 or 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 If swallow_error is True, then this will catch and discard any OSError that |
| 77 is thrown. This lets you run later BuildSteps if the current one fails. |
| 78 """ |
| 79 def __init__(self, name, swallow_error=False): |
| 80 self.name = name |
| 81 self.swallow_error = swallow_error |
| 82 |
| 83 def __enter__(self): |
| 84 print '@@@BUILD_STEP %s@@@' % self.name |
| 85 |
| 86 def __exit__(self, type, value, traceback): |
| 87 if value: |
| 88 print '@@@STEP_FAILURE@@@' |
| 89 if self.swallow_error and isinstance(value, OSError): |
| 90 return True |
| 91 |
| 92 |
| 93 def RunBot(parse_name, custom_steps): |
| 94 """ |
| 95 The main function for running a buildbot. |
| 96 |
| 97 A buildbot script should invoke this once. The parse_name function will be |
| 98 called with the name of the buildbot and should return an instance of |
| 99 BuildInfo. This function will then set up the bot, build the SDK etc. When |
| 100 that's done, it will call custom_steps, passing in the BuildInfo object. |
| 101 |
| 102 In that, you can perform any bot-specific build steps. |
| 103 |
| 104 This function will not return. It will call sys.exit() with an appropriate |
| 105 exit code. |
| 106 """ |
| 107 if len(sys.argv) == 0: |
| 108 print 'Script pathname not known, giving up.' |
| 109 sys.exit(1) |
| 110 |
| 111 name, is_buildbot = GetBotName() |
| 112 build_info = parse_name(name, is_buildbot) |
| 113 if not build_info: |
| 114 print 'Could not handle unfamiliar bot name "%s".' % name |
| 115 sys.exit(1) |
| 116 |
| 117 # Print out the buildinfo for easy debugging. |
| 118 build_info.PrintBuildInfo() |
| 119 |
| 120 # Make sure we are in the dart directory |
| 121 os.chdir(DART_PATH) |
| 122 |
| 123 try: |
| 124 Clobber(build_info.mode) |
| 125 BuildSDK(build_info.mode, build_info.system) |
| 126 |
| 127 custom_steps(build_info) |
| 128 except OSError as e: |
| 129 sys.exit(e.errno) |
| 130 |
| 131 sys.exit(0) |
| 132 |
| 133 |
| 134 def GetBotName(): |
| 135 """ |
| 136 Gets the name of the current buildbot. |
| 137 |
| 138 Returns a tuple of the buildbot name and a flag to indicate if we are actually |
| 139 a buildbot (True), or just a user pretending to be one (False). |
| 140 """ |
| 141 # For testing the bot locally, allow the user to pass in a buildbot name. |
| 142 parser = optparse.OptionParser() |
| 143 parser.add_option('-n', '--name', dest='name', help='The name of the build' |
| 144 'bot you would like to emulate (ex: vm-mac-debug)', default=None) |
| 145 args, _ = parser.parse_args() |
| 146 |
| 147 if args.name: |
| 148 return args.name, False |
| 149 |
| 150 name = os.environ.get(BUILDER_NAME) |
| 151 if not name: |
| 152 print 'Use -n $BUILDBOT_NAME for the bot you would like to emulate.' |
| 153 sys.exit(1) |
| 154 |
| 155 return name, True |
| 156 |
| 157 |
| 158 def Clobber(mode): |
| 159 """ |
| 160 Clobbers the builder before we do the build, if appropriate. |
| 161 |
| 162 - mode: either 'debug' or 'release' |
| 163 """ |
| 164 if os.environ.get(BUILDER_CLOBBER) != "1": |
| 165 return |
| 166 |
| 167 with BuildStep('Clobber'): |
| 168 cmd = [sys.executable, |
| 169 './tools/clean_output_directory.py', |
| 170 '--mode=' + mode] |
| 171 print 'Clobbering %s' % (' '.join(cmd)) |
| 172 RunProcess(cmd) |
| 173 |
| 174 |
| 175 def BuildSDK(mode, system): |
| 176 """ |
| 177 Builds the SDK. |
| 178 |
| 179 - mode: either 'debug' or 'release' |
| 180 - system: either 'linux', 'mac', or 'win7' |
| 181 """ |
| 182 with BuildStep('Build SDK'): |
| 183 args = [sys.executable, './tools/build.py', '--mode=' + mode, 'create_sdk'] |
| 184 print 'Building SDK: %s' % (' '.join(args)) |
| 185 RunProcess(args) |
| 186 |
| 187 |
| 188 def RunTest(name, build_info, targets, flags=None): |
| 189 """ |
| 190 Runs test.py with the given settings. |
| 191 """ |
| 192 if not flags: |
| 193 flags = [] |
| 194 |
| 195 step_name = GetStepName(name, flags) |
| 196 with BuildStep(step_name): |
| 197 sys.stdout.flush() |
| 198 |
| 199 cmd = [ |
| 200 sys.executable, os.path.join(os.curdir, 'tools', 'test.py'), |
| 201 '--step_name=' + step_name, |
| 202 '--mode=' + build_info.mode, |
| 203 '--compiler=' + build_info.compiler, |
| 204 '--runtime=' + build_info.runtime, |
| 205 '--progress=buildbot', |
| 206 '-v', '--time', '--use-sdk', '--report' |
| 207 ] |
| 208 |
| 209 if build_info.checked: |
| 210 cmd.append('--checked') |
| 211 |
| 212 cmd.extend(flags) |
| 213 cmd.extend(targets) |
| 214 |
| 215 print 'Running: %s' % (' '.join(cmd)) |
| 216 RunProcess(cmd) |
| 217 |
| 218 |
| 219 def RunProcess(command): |
| 220 """ |
| 221 Runs command. |
| 222 |
| 223 If a non-zero exit code is returned, raises an OSError with errno as the exit |
| 224 code. |
| 225 """ |
| 226 exit_code = subprocess.call(command, env=NO_COLOR_ENV) |
| 227 if exit_code != 0: |
| 228 raise OSError(exit_code) |
| 229 |
| 230 |
| 231 def GetStepName(name, flags): |
| 232 """ |
| 233 Filters out flags with '=' as this breaks the /stats feature of the buildbot. |
| 234 """ |
| 235 flags = [x for x in flags if not '=' in x] |
| 236 return ('%s tests %s' % (name, ' '.join(flags))).strip() |
OLD | NEW |