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 |