| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 Google Inc. All rights reserved. | 2 # Copyright (c) 2012 Google Inc. 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 """Argument-less script to select what to run on the buildbots.""" | 6 """Argument-less script to select what to run on the buildbots.""" |
| 7 | 7 |
| 8 import filecmp | |
| 9 import os | 8 import os |
| 10 import shutil | 9 import shutil |
| 11 import subprocess | 10 import subprocess |
| 12 import sys | 11 import sys |
| 13 | 12 |
| 14 | 13 |
| 15 if sys.platform in ['win32', 'cygwin']: | |
| 16 EXE_SUFFIX = '.exe' | |
| 17 else: | |
| 18 EXE_SUFFIX = '' | |
| 19 | |
| 20 | |
| 21 BUILDBOT_DIR = os.path.dirname(os.path.abspath(__file__)) | 14 BUILDBOT_DIR = os.path.dirname(os.path.abspath(__file__)) |
| 22 TRUNK_DIR = os.path.dirname(BUILDBOT_DIR) | 15 TRUNK_DIR = os.path.dirname(BUILDBOT_DIR) |
| 23 ROOT_DIR = os.path.dirname(TRUNK_DIR) | 16 ROOT_DIR = os.path.dirname(TRUNK_DIR) |
| 24 ANDROID_DIR = os.path.join(ROOT_DIR, 'android') | |
| 25 CMAKE_DIR = os.path.join(ROOT_DIR, 'cmake') | 17 CMAKE_DIR = os.path.join(ROOT_DIR, 'cmake') |
| 26 CMAKE_BIN_DIR = os.path.join(CMAKE_DIR, 'bin') | 18 CMAKE_BIN_DIR = os.path.join(CMAKE_DIR, 'bin') |
| 27 OUT_DIR = os.path.join(TRUNK_DIR, 'out') | 19 OUT_DIR = os.path.join(TRUNK_DIR, 'out') |
| 28 | 20 |
| 29 | 21 |
| 30 def CallSubProcess(*args, **kwargs): | 22 def CallSubProcess(*args, **kwargs): |
| 31 """Wrapper around subprocess.call which treats errors as build exceptions.""" | 23 """Wrapper around subprocess.call which treats errors as build exceptions.""" |
| 32 with open(os.devnull) as devnull_fd: | 24 with open(os.devnull) as devnull_fd: |
| 33 retcode = subprocess.call(stdin=devnull_fd, *args, **kwargs) | 25 retcode = subprocess.call(stdin=devnull_fd, *args, **kwargs) |
| 34 if retcode != 0: | 26 if retcode != 0: |
| (...skipping 27 matching lines...) Expand all Loading... |
| 62 cwd=CMAKE_DIR) | 54 cwd=CMAKE_DIR) |
| 63 | 55 |
| 64 print '@@@BUILD_STEP Build CMake@@@' | 56 print '@@@BUILD_STEP Build CMake@@@' |
| 65 CallSubProcess( | 57 CallSubProcess( |
| 66 ['/bin/bash', 'bootstrap', '--prefix=%s' % CMAKE_DIR], | 58 ['/bin/bash', 'bootstrap', '--prefix=%s' % CMAKE_DIR], |
| 67 cwd=CMAKE_DIR) | 59 cwd=CMAKE_DIR) |
| 68 | 60 |
| 69 CallSubProcess( ['make', 'cmake'], cwd=CMAKE_DIR) | 61 CallSubProcess( ['make', 'cmake'], cwd=CMAKE_DIR) |
| 70 | 62 |
| 71 | 63 |
| 72 _ANDROID_SETUP = 'source build/envsetup.sh && lunch full-eng' | |
| 73 | |
| 74 | |
| 75 def PrepareAndroidTree(): | |
| 76 """Prepare an Android tree to run 'android' format tests.""" | |
| 77 if os.environ['BUILDBOT_CLOBBER'] == '1': | |
| 78 print '@@@BUILD_STEP Clobber Android checkout@@@' | |
| 79 shutil.rmtree(ANDROID_DIR) | |
| 80 | |
| 81 # (Re)create the directory so that the following steps will succeed. | |
| 82 if not os.path.isdir(ANDROID_DIR): | |
| 83 os.mkdir(ANDROID_DIR) | |
| 84 | |
| 85 # We use a manifest from the gyp project listing pinned revisions of AOSP to | |
| 86 # use, to ensure that we test against a stable target. This needs to be | |
| 87 # updated to pick up new build system changes sometimes, so we must test if | |
| 88 # it has changed. | |
| 89 manifest_filename = 'aosp_manifest.xml' | |
| 90 gyp_manifest = os.path.join(BUILDBOT_DIR, manifest_filename) | |
| 91 android_manifest = os.path.join(ANDROID_DIR, '.repo', 'manifests', | |
| 92 manifest_filename) | |
| 93 manifest_is_current = (os.path.isfile(android_manifest) and | |
| 94 filecmp.cmp(gyp_manifest, android_manifest)) | |
| 95 if not manifest_is_current: | |
| 96 # It's safe to repeat these steps, so just do them again to make sure we are | |
| 97 # in a good state. | |
| 98 print '@@@BUILD_STEP Initialize Android checkout@@@' | |
| 99 CallSubProcess( | |
| 100 ['repo', 'init', | |
| 101 '-u', 'https://android.googlesource.com/platform/manifest', | |
| 102 '-b', 'master', | |
| 103 '-g', 'all,-notdefault,-device,-darwin,-mips,-x86'], | |
| 104 cwd=ANDROID_DIR) | |
| 105 shutil.copy(gyp_manifest, android_manifest) | |
| 106 | |
| 107 print '@@@BUILD_STEP Sync Android@@@' | |
| 108 CallSubProcess(['repo', 'sync', '-j4', '-m', manifest_filename], | |
| 109 cwd=ANDROID_DIR) | |
| 110 | |
| 111 # If we already built the system image successfully and didn't sync to a new | |
| 112 # version of the source, skip running the build again as it's expensive even | |
| 113 # when there's nothing to do. | |
| 114 system_img = os.path.join(ANDROID_DIR, 'out', 'target', 'product', 'generic', | |
| 115 'system.img') | |
| 116 if manifest_is_current and os.path.isfile(system_img): | |
| 117 return | |
| 118 | |
| 119 print '@@@BUILD_STEP Build Android@@@' | |
| 120 CallSubProcess( | |
| 121 ['/bin/bash', | |
| 122 '-c', '%s && make -j4' % _ANDROID_SETUP], | |
| 123 cwd=ANDROID_DIR) | |
| 124 | |
| 125 | |
| 126 def StartAndroidEmulator(): | |
| 127 """Start an android emulator from the built android tree.""" | |
| 128 print '@@@BUILD_STEP Start Android emulator@@@' | |
| 129 | |
| 130 CallSubProcess(['/bin/bash', '-c', | |
| 131 '%s && adb kill-server ' % _ANDROID_SETUP], | |
| 132 cwd=ANDROID_DIR) | |
| 133 | |
| 134 # If taskset is available, use it to force adbd to run only on one core, as, | |
| 135 # sadly, it improves its reliability (see crbug.com/268450). | |
| 136 adbd_wrapper = '' | |
| 137 with open(os.devnull, 'w') as devnull_fd: | |
| 138 if subprocess.call(['which', 'taskset'], stdout=devnull_fd) == 0: | |
| 139 adbd_wrapper = 'taskset -c 0' | |
| 140 CallSubProcess(['/bin/bash', '-c', | |
| 141 '%s && %s adb start-server ' % (_ANDROID_SETUP, adbd_wrapper)], | |
| 142 cwd=ANDROID_DIR) | |
| 143 | |
| 144 subprocess.Popen( | |
| 145 ['/bin/bash', '-c', | |
| 146 '%s && emulator -no-window' % _ANDROID_SETUP], | |
| 147 cwd=ANDROID_DIR) | |
| 148 CallSubProcess( | |
| 149 ['/bin/bash', '-c', | |
| 150 '%s && adb wait-for-device' % _ANDROID_SETUP], | |
| 151 cwd=ANDROID_DIR) | |
| 152 | |
| 153 | |
| 154 def StopAndroidEmulator(): | |
| 155 """Stop all android emulators.""" | |
| 156 print '@@@BUILD_STEP Stop Android emulator@@@' | |
| 157 # If this fails, it's because there is no emulator running. | |
| 158 subprocess.call(['pkill', 'emulator.*']) | |
| 159 | |
| 160 | |
| 161 def GypTestFormat(title, format=None, msvs_version=None, tests=[]): | 64 def GypTestFormat(title, format=None, msvs_version=None, tests=[]): |
| 162 """Run the gyp tests for a given format, emitting annotator tags. | 65 """Run the gyp tests for a given format, emitting annotator tags. |
| 163 | 66 |
| 164 See annotator docs at: | 67 See annotator docs at: |
| 165 https://sites.google.com/a/chromium.org/dev/developers/testing/chromium-buil
d-infrastructure/buildbot-annotations | 68 https://sites.google.com/a/chromium.org/dev/developers/testing/chromium-buil
d-infrastructure/buildbot-annotations |
| 166 Args: | 69 Args: |
| 167 format: gyp format to test. | 70 format: gyp format to test. |
| 168 Returns: | 71 Returns: |
| 169 0 for sucesss, 1 for failure. | 72 0 for sucesss, 1 for failure. |
| 170 """ | 73 """ |
| 171 if not format: | 74 if not format: |
| 172 format = title | 75 format = title |
| 173 | 76 |
| 174 print '@@@BUILD_STEP ' + title + '@@@' | 77 print '@@@BUILD_STEP ' + title + '@@@' |
| 175 sys.stdout.flush() | 78 sys.stdout.flush() |
| 176 env = os.environ.copy() | 79 env = os.environ.copy() |
| 177 if msvs_version: | 80 if msvs_version: |
| 178 env['GYP_MSVS_VERSION'] = msvs_version | 81 env['GYP_MSVS_VERSION'] = msvs_version |
| 179 command = ' '.join( | 82 command = ' '.join( |
| 180 [sys.executable, 'gyp/gyptest.py', | 83 [sys.executable, 'gyp/gyptest.py', |
| 181 '--all', | 84 '--all', |
| 182 '--passed', | 85 '--passed', |
| 183 '--format', format, | 86 '--format', format, |
| 184 '--path', CMAKE_BIN_DIR, | 87 '--path', CMAKE_BIN_DIR, |
| 185 '--chdir', 'gyp'] + tests) | 88 '--chdir', 'gyp'] + tests) |
| 186 if format == 'android': | 89 retcode = subprocess.call(command, cwd=ROOT_DIR, env=env, shell=True) |
| 187 # gyptest needs the environment setup from envsetup/lunch in order to build | |
| 188 # using the 'android' backend, so this is done in a single shell. | |
| 189 retcode = subprocess.call( | |
| 190 ['/bin/bash', | |
| 191 '-c', '%s && cd %s && %s' % (_ANDROID_SETUP, ROOT_DIR, command)], | |
| 192 cwd=ANDROID_DIR, env=env) | |
| 193 else: | |
| 194 retcode = subprocess.call(command, cwd=ROOT_DIR, env=env, shell=True) | |
| 195 if retcode: | 90 if retcode: |
| 196 # Emit failure tag, and keep going. | 91 # Emit failure tag, and keep going. |
| 197 print '@@@STEP_FAILURE@@@' | 92 print '@@@STEP_FAILURE@@@' |
| 198 return 1 | 93 return 1 |
| 199 return 0 | 94 return 0 |
| 200 | 95 |
| 201 | 96 |
| 202 def GypBuild(): | 97 def GypBuild(): |
| 203 # Dump out/ directory. | 98 # Dump out/ directory. |
| 204 print '@@@BUILD_STEP cleanup@@@' | 99 print '@@@BUILD_STEP cleanup@@@' |
| 205 print 'Removing %s...' % OUT_DIR | 100 print 'Removing %s...' % OUT_DIR |
| 206 shutil.rmtree(OUT_DIR, ignore_errors=True) | 101 shutil.rmtree(OUT_DIR, ignore_errors=True) |
| 207 print 'Done.' | 102 print 'Done.' |
| 208 | 103 |
| 209 retcode = 0 | 104 retcode = 0 |
| 210 # The Android gyp bot runs on linux so this must be tested first. | 105 if sys.platform.startswith('linux'): |
| 211 if os.environ['BUILDBOT_BUILDERNAME'] == 'gyp-android': | |
| 212 PrepareAndroidTree() | |
| 213 StartAndroidEmulator() | |
| 214 try: | |
| 215 retcode += GypTestFormat('android') | |
| 216 finally: | |
| 217 StopAndroidEmulator() | |
| 218 elif sys.platform.startswith('linux'): | |
| 219 retcode += GypTestFormat('ninja') | 106 retcode += GypTestFormat('ninja') |
| 220 retcode += GypTestFormat('make') | 107 retcode += GypTestFormat('make') |
| 221 PrepareCmake() | 108 PrepareCmake() |
| 222 retcode += GypTestFormat('cmake') | 109 retcode += GypTestFormat('cmake') |
| 223 elif sys.platform == 'darwin': | 110 elif sys.platform == 'darwin': |
| 224 retcode += GypTestFormat('ninja') | 111 retcode += GypTestFormat('ninja') |
| 225 retcode += GypTestFormat('xcode') | 112 retcode += GypTestFormat('xcode') |
| 226 retcode += GypTestFormat('make') | 113 retcode += GypTestFormat('make') |
| 227 elif sys.platform == 'win32': | 114 elif sys.platform == 'win32': |
| 228 retcode += GypTestFormat('ninja') | 115 retcode += GypTestFormat('ninja') |
| (...skipping 11 matching lines...) Expand all Loading... |
| 240 # TODO(bradnelson): once the annotator supports a postscript (section for | 127 # TODO(bradnelson): once the annotator supports a postscript (section for |
| 241 # after the build proper that could be used for cumulative failures), | 128 # after the build proper that could be used for cumulative failures), |
| 242 # use that instead of this. This isolates the final return value so | 129 # use that instead of this. This isolates the final return value so |
| 243 # that it isn't misattributed to the last stage. | 130 # that it isn't misattributed to the last stage. |
| 244 print '@@@BUILD_STEP failures@@@' | 131 print '@@@BUILD_STEP failures@@@' |
| 245 sys.exit(retcode) | 132 sys.exit(retcode) |
| 246 | 133 |
| 247 | 134 |
| 248 if __name__ == '__main__': | 135 if __name__ == '__main__': |
| 249 GypBuild() | 136 GypBuild() |
| OLD | NEW |