Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / native_client / buildbot / buildbot_standard.py
1 #!/usr/bin/python
2 # Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 # Enable 'with' statements in Python 2.5
7 from __future__ import with_statement
8
9 import os.path
10 import re
11 import subprocess
12 import sys
13 import time
14
15 from buildbot_lib import (
16     BuildContext, BuildStatus, Command, EnsureDirectoryExists,
17     ParseStandardCommandLine, RemoveDirectory, RemoveGypBuildDirectories,
18     RemoveSconsBuildDirectories, RunBuild, SCons, Step, StepLink,
19     StepText, TryToCleanContents)
20
21
22 # Windows-specific environment manipulation
23 def SetupWindowsEnvironment(context):
24   # Poke around looking for MSVC.  We should do something more principled in
25   # the future.
26
27   # The name of Program Files can differ, depending on the bittage of Windows.
28   program_files = r'c:\Program Files (x86)'
29   if not os.path.exists(program_files):
30     program_files = r'c:\Program Files'
31     if not os.path.exists(program_files):
32       raise Exception('Cannot find the Program Files directory!')
33
34   # The location of MSVC can differ depending on the version.
35   msvc_locs = [
36       ('Microsoft Visual Studio 12.0', 'VS120COMNTOOLS', '2013'),
37       ('Microsoft Visual Studio 10.0', 'VS100COMNTOOLS', '2010'),
38       ('Microsoft Visual Studio 9.0', 'VS90COMNTOOLS', '2008'),
39       ('Microsoft Visual Studio 8.0', 'VS80COMNTOOLS', '2005'),
40   ]
41
42   for dirname, comntools_var, gyp_msvs_version in msvc_locs:
43     msvc = os.path.join(program_files, dirname)
44     context.SetEnv('GYP_MSVS_VERSION', gyp_msvs_version)
45     if os.path.exists(msvc):
46       break
47   else:
48     # The break statement did not execute.
49     raise Exception('Cannot find MSVC!')
50
51   # Put MSVC in the path.
52   vc = os.path.join(msvc, 'VC')
53   comntools = os.path.join(msvc, 'Common7', 'Tools')
54   perf = os.path.join(msvc, 'Team Tools', 'Performance Tools')
55   context.SetEnv('PATH', os.pathsep.join([
56       context.GetEnv('PATH'),
57       vc,
58       comntools,
59       perf]))
60
61   # SCons needs this variable to find vsvars.bat.
62   # The end slash is needed because the batch files expect it.
63   context.SetEnv(comntools_var, comntools + '\\')
64
65   # This environment variable will SCons to print debug info while it searches
66   # for MSVC.
67   context.SetEnv('SCONS_MSCOMMON_DEBUG', '-')
68
69   # Needed for finding devenv.
70   context['msvc'] = msvc
71
72   # The context on other systems has GYP_DEFINES set, set it for windows to be
73   # able to save and restore without KeyError.
74   context.SetEnv('GYP_DEFINES', '')
75
76
77 def SetupGypDefines(context, extra_vars=[]):
78   context.SetEnv('GYP_DEFINES', ' '.join(context['gyp_vars'] + extra_vars))
79
80
81 def SetupLinuxEnvironment(context):
82   SetupGypDefines(context, ['target_arch='+context['gyp_arch']])
83
84
85 def SetupMacEnvironment(context):
86   SetupGypDefines(context)
87   context.SetEnv('GYP_GENERATORS', 'ninja')
88
89
90 def SetupContextVars(context):
91   # The branch is set to native_client on the main bots, on the trybots it's
92   # set to ''.  Otherwise, we should assume a particular branch is being used.
93   context['branch'] = os.environ.get('BUILDBOT_BRANCH', 'native_client')
94   context['off_trunk'] = context['branch'] not in ['native_client', '']
95
96
97 def ValidatorTest(context, architecture, validator, warn_only=False):
98   cmd = [
99       sys.executable,
100       'tests/abi_corpus/validator_regression_test.py',
101       '--keep-going',
102       '--validator', validator,
103       '--arch', architecture
104   ]
105   if warn_only:
106     cmd.append('--warn-only')
107   Command(context, cmd=cmd)
108
109
110 def SummarizeCoverage(context):
111   Command(context, [
112       sys.executable,
113       'tools/coverage_summary.py',
114       context['platform'] + '-' + context['default_scons_platform'],
115   ])
116
117
118 def ArchiveCoverage(context):
119   gsutil = '/b/build/third_party/gsutil/gsutil'
120   gsd_url = 'http://gsdview.appspot.com/nativeclient-coverage2/revs'
121   variant_name = ('coverage-' + context['platform'] + '-' +
122                   context['default_scons_platform'])
123   coverage_path = variant_name + '/html/index.html'
124   revision = os.environ.get('BUILDBOT_REVISION', 'None')
125   link_url = gsd_url + '/' + revision + '/' + coverage_path
126   gsd_base = 'gs://nativeclient-coverage2/revs'
127   gs_path = gsd_base + '/' + revision + '/' + variant_name
128   cov_dir = 'scons-out/' + variant_name + '/coverage'
129   # Copy lcov file.
130   Command(context, [
131       sys.executable, gsutil,
132       'cp', '-a', 'public-read',
133       cov_dir + '/coverage.lcov',
134       gs_path + '/coverage.lcov',
135   ])
136   # Copy html.
137   Command(context, [
138       sys.executable, gsutil,
139       'cp', '-R', '-a', 'public-read',
140       'html', gs_path,
141   ], cwd=cov_dir)
142   print '@@@STEP_LINK@view@%s@@@' % link_url
143
144
145 def CommandGypBuild(context):
146   if context.Windows():
147     Command(
148         context,
149         cmd=[os.path.join(context['msvc'], 'Common7', 'IDE', 'devenv.com'),
150              r'build\all.sln',
151              '/build', context['gyp_mode']])
152   elif context.Linux():
153     Command(context, cmd=['make', '-C', '..', '-k',
154                           '-j%d' % context['max_jobs'], 'V=1',
155                           'BUILDTYPE=' + context['gyp_mode']])
156   elif context.Mac():
157     Command(context, cmd=[
158         'ninja', '-k', '0', '-C', '../out/' + context['gyp_mode']])
159   else:
160     raise Exception('Unknown platform')
161
162
163 def CommandGypGenerate(context):
164   Command(
165           context,
166           cmd=[
167               sys.executable,
168               'native_client/build/gyp_nacl',
169               'native_client/build/all.gyp',
170               ],
171           cwd='..')
172
173
174 def CommandGclientRunhooks(context):
175   if context.Windows():
176     gclient = 'gclient.bat'
177   else:
178     gclient = 'gclient'
179   print 'Running gclient runhooks...'
180   print 'GYP_DEFINES=' + context.GetEnv('GYP_DEFINES')
181   Command(context, cmd=[gclient, 'runhooks', '--force'])
182
183
184 def BuildScript(status, context):
185   inside_toolchain = context['inside_toolchain']
186
187   # Clean out build directories.
188   with Step('clobber', status):
189     RemoveSconsBuildDirectories()
190     RemoveGypBuildDirectories()
191
192   with Step('cleanup_temp', status):
193     # Picking out drive letter on which the build is happening so we can use
194     # it for the temp directory.
195     if context.Windows():
196       build_drive = os.path.splitdrive(os.path.abspath(__file__))[0]
197       tmp_dir = os.path.join(build_drive, os.path.sep + 'temp')
198       context.SetEnv('TEMP', tmp_dir)
199       context.SetEnv('TMP', tmp_dir)
200     else:
201       tmp_dir = '/tmp'
202     print 'Making sure %s exists...' % tmp_dir
203     EnsureDirectoryExists(tmp_dir)
204     print 'Cleaning up the contents of %s...' % tmp_dir
205     # Only delete files and directories like:
206     # a) C:\temp\83C4.tmp
207     # b) /tmp/.org.chromium.Chromium.EQrEzl
208     file_name_re = re.compile(
209         r'[\\/]([0-9a-fA-F]+\.tmp|\.org\.chrom\w+\.Chrom\w+\..+)$')
210     file_name_filter = lambda fn: file_name_re.search(fn) is not None
211     TryToCleanContents(tmp_dir, file_name_filter)
212
213     # Mac has an additional temporary directory; clean it up.
214     # TODO(bradnelson): Fix Mac Chromium so that these temp files are created
215     #     with open() + unlink() so that they will not get left behind.
216     if context.Mac():
217       subprocess.call(
218           "find /var/folders -name '.org.chromium.*' -exec rm -rfv '{}' ';'",
219           shell=True)
220       subprocess.call(
221           "find /var/folders -name '.com.google.Chrome*' -exec rm -rfv '{}' ';'",
222           shell=True)
223
224   # Skip over hooks when run inside the toolchain build because
225   # download_toolchains would overwrite the toolchain build.
226   if inside_toolchain:
227     with Step('gyp_generate_only', status):
228       CommandGypGenerate(context)
229   else:
230     with Step('gclient_runhooks', status):
231       CommandGclientRunhooks(context)
232
233   if context['clang']:
234     with Step('update_clang', status):
235       Command(context, cmd=['../tools/clang/scripts/update.sh'])
236
237   # Just build both bitages of validator and test for --validator mode.
238   if context['validator']:
239     with Step('build ncval-x86-32', status):
240       SCons(context, platform='x86-32', parallel=True, args=['ncval'])
241     with Step('build ncval-x86-64', status):
242       SCons(context, platform='x86-64', parallel=True, args=['ncval'])
243
244     with Step('build ragel_validator-32', status):
245       SCons(context, platform='x86-32', parallel=True, args=['ncval_new'])
246     with Step('build ragel_validator-64', status):
247       SCons(context, platform='x86-64', parallel=True, args=['ncval_new'])
248
249     with Step('predownload validator corpus', status):
250       Command(context,
251           cmd=[sys.executable,
252                'tests/abi_corpus/validator_regression_test.py',
253                '--download-only'])
254
255     with Step('validator_regression_test current x86-32', status,
256         halt_on_fail=False):
257       ValidatorTest(
258           context, 'x86-32', 'scons-out/opt-linux-x86-32/staging/ncval')
259     with Step('validator_regression_test current x86-64', status,
260         halt_on_fail=False):
261       ValidatorTest(
262           context, 'x86-64', 'scons-out/opt-linux-x86-64/staging/ncval')
263
264     with Step('validator_regression_test ragel x86-32', status,
265         halt_on_fail=False):
266       ValidatorTest(
267           context, 'x86-32',
268           'scons-out/opt-linux-x86-32/staging/ncval_new')
269     with Step('validator_regression_test ragel x86-64', status,
270         halt_on_fail=False):
271       ValidatorTest(
272           context, 'x86-64',
273           'scons-out/opt-linux-x86-64/staging/ncval_new')
274
275     with Step('validator_diff32_tests', status, halt_on_fail=False):
276       SCons(context, platform='x86-32', args=['validator_diff_tests'])
277     with Step('validator_diff64_tests', status, halt_on_fail=False):
278       SCons(context, platform='x86-64', args=['validator_diff_tests'])
279     return
280
281   # Run checkdeps script to vet #includes.
282   with Step('checkdeps', status):
283     Command(context, cmd=[sys.executable, 'tools/checkdeps/checkdeps.py'])
284
285   # Make sure our Gyp build is working.
286   if not context['no_gyp']:
287     with Step('gyp_compile', status):
288       CommandGypBuild(context)
289
290   # On a subset of Linux builds, build Breakpad tools for testing.
291   if context['use_breakpad_tools']:
292     with Step('breakpad configure', status):
293       Command(context, cmd=['mkdir', '-p', 'breakpad-out'])
294       Command(context, cwd='breakpad-out',
295               cmd=['bash', '../../breakpad/configure',
296                    'CXXFLAGS=-I../..'])  # For third_party/lss
297     with Step('breakpad make', status):
298       Command(context, cmd=['make', '-j%d' % context['max_jobs']],
299               cwd='breakpad-out')
300
301   # The main compile step.
302   with Step('scons_compile', status):
303     SCons(context, parallel=True, args=[])
304
305   if context['coverage']:
306     with Step('collect_coverage', status, halt_on_fail=True):
307       SCons(context, args=['coverage'])
308     with Step('summarize_coverage', status, halt_on_fail=False):
309       SummarizeCoverage(context)
310     slave_type = os.environ.get('BUILDBOT_SLAVE_TYPE')
311     if slave_type != 'Trybot' and slave_type is not None:
312       with Step('archive_coverage', status, halt_on_fail=True):
313         ArchiveCoverage(context)
314     return
315
316   ### BEGIN tests ###
317   with Step('small_tests', status, halt_on_fail=False):
318     SCons(context, args=['small_tests'])
319   with Step('medium_tests', status, halt_on_fail=False):
320     SCons(context, args=['medium_tests'])
321   with Step('large_tests', status, halt_on_fail=False):
322     SCons(context, args=['large_tests'])
323
324   with Step('compile IRT tests', status):
325     SCons(context, parallel=True, mode=['nacl_irt_test'])
326
327   with Step('small_tests under IRT', status, halt_on_fail=False):
328     SCons(context, mode=context['default_scons_mode'] + ['nacl_irt_test'],
329           args=['small_tests_irt'])
330   with Step('medium_tests under IRT', status, halt_on_fail=False):
331     SCons(context, mode=context['default_scons_mode'] + ['nacl_irt_test'],
332           args=['medium_tests_irt'])
333
334   ### END tests ###
335
336   if not context['no_gyp']:
337     # Build with ragel-based validator using GYP.
338     gyp_defines_save = context.GetEnv('GYP_DEFINES')
339     context.SetEnv('GYP_DEFINES',
340                    ' '.join([gyp_defines_save, 'nacl_validator_ragel=0']))
341     with Step('gyp_compile_noragel', status):
342       # Clobber GYP build to recompile necessary files with new preprocessor macro
343       # definitions.  It is done because some build systems (such as GNU Make,
344       # MSBuild etc.) do not consider compiler arguments as a dependency.
345       RemoveGypBuildDirectories()
346       CommandGypGenerate(context)
347       CommandGypBuild(context)
348     context.SetEnv('GYP_DEFINES', gyp_defines_save)
349
350   # Build with ragel-based validator using scons.
351   with Step('scons_compile_noragel', status):
352     SCons(context, parallel=True, args=['validator_ragel=0'])
353
354   # Smoke tests for the R-DFA validator.
355   with Step('validator_noragel_tests', status):
356     args = ['validator_ragel=0',
357             'small_tests',
358             'medium_tests',
359             'large_tests',
360             ]
361     # Add nacl_irt_test mode to be able to run run_hello_world_test_irt that
362     # tests validation of the IRT.
363     SCons(context,
364           mode=context['default_scons_mode'] + ['nacl_irt_test'],
365           args=args)
366
367
368 def Main():
369   # TODO(ncbray) make buildbot scripts composable to support toolchain use case.
370   context = BuildContext()
371   status = BuildStatus(context)
372   ParseStandardCommandLine(context)
373   SetupContextVars(context)
374   if context.Windows():
375     SetupWindowsEnvironment(context)
376   elif context.Linux():
377     SetupLinuxEnvironment(context)
378   elif context.Mac():
379     SetupMacEnvironment(context)
380   else:
381     raise Exception("Unsupported platform.")
382   RunBuild(BuildScript, status)
383
384
385 def TimedMain():
386   start_time = time.time()
387   try:
388     Main()
389   finally:
390     time_taken = time.time() - start_time
391     print 'RESULT BuildbotTime: total= %.3f minutes' % (time_taken / 60)
392
393
394 if __name__ == '__main__':
395   TimedMain()