Add a new script bb_host_steps.py which handles all host side steps.

BUG=154525
NOTRY=True

Review URL: https://chromiumcodereview.appspot.com/15261003

git-svn-id: http://src.chromium.org/svn/trunk/src/build@204970 4ff67af0-8c30-449e-8e8b-ad334ec8d88c
This commit is contained in:
sivachandra@chromium.org 2013-06-07 23:14:39 +00:00
Родитель a6fa783a56
Коммит 9baabbd90d
6 изменённых файлов: 258 добавлений и 233 удалений

Просмотреть файл

@ -40,7 +40,8 @@ def CommonChecks(input_api, output_api):
output_api,
white_list=[r'PRESUBMIT\.py$', r'buildbot/.*\.py$'],
extra_paths_list=[
J(), J('..', '..', 'third_party', 'android_testrunner')]))
J(), J('..', '..', 'third_party', 'android_testrunner'),
J('buildbot')]))
output.extend(input_api.canned_checks.RunUnitTestsInDirectory(
input_api, output_api, J('buildbot', 'tests')))

Просмотреть файл

@ -5,15 +5,13 @@
import collections
import glob
import json
import multiprocessing
import optparse
import os
import pipes
import shutil
import subprocess
import sys
import bb_utils
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from pylib import android_commands
from pylib import buildbot_report
@ -25,8 +23,6 @@ sys.path.append(os.path.join(
import errors
TESTING = 'BUILDBOT_TESTING' in os.environ
CHROME_SRC = constants.DIR_SOURCE_ROOT
# Describes an instrumation test suite:
@ -61,34 +57,7 @@ INSTRUMENTATION_TESTS = dict((suite.name, suite) for suite in [
VALID_TESTS = set(['chromedriver', 'ui', 'unit', 'webkit', 'webkit_layout'])
def SpawnCmd(command):
"""Spawn a process without waiting for termination."""
print '>', ' '.join(map(pipes.quote, command))
sys.stdout.flush()
if TESTING:
class MockPopen(object):
@staticmethod
def wait():
return 0
return MockPopen()
return subprocess.Popen(command, cwd=CHROME_SRC)
def RunCmd(command, flunk_on_failure=True, halt_on_failure=False):
"""Run a command relative to the chrome source root."""
code = SpawnCmd(command).wait()
print '<', ' '.join(map(pipes.quote, command))
if code != 0:
print 'ERROR: process exited with code %d' % code
if flunk_on_failure:
buildbot_report.PrintError()
else:
buildbot_report.PrintWarning()
# Allow steps to have both halting (i.e. 1) and non-halting exit codes.
if code != 0 and code != 88 and halt_on_failure:
raise OSError()
return code
RunCmd = bb_utils.RunCmd
# multiprocessing map_async requires a top-level function for pickle library.
@ -105,7 +74,7 @@ def RebootDevices():
buildbot_report.PrintNamedStep('Reboot devices')
# Early return here to avoid presubmit dependence on adb,
# which might not exist in this checkout.
if TESTING:
if bb_utils.TESTING:
return
devices = android_commands.GetAttachedDevices()
print 'Rebooting: %s' % devices
@ -260,7 +229,7 @@ def MainTestWrapper(options):
# Spawn logcat monitor
logcat_dir = os.path.join(CHROME_SRC, 'out/logcat')
shutil.rmtree(logcat_dir, ignore_errors=True)
SpawnCmd(['build/android/adb_logcat_monitor.py', logcat_dir])
bb_utils.SpawnCmd(['build/android/adb_logcat_monitor.py', logcat_dir])
# Wait for logcat_monitor to pull existing logcat
RunCmd(['sleep', '5'])
@ -312,20 +281,7 @@ def MainTestWrapper(options):
def main(argv):
parser = optparse.OptionParser()
def convert_json(option, _, value, parser):
setattr(parser.values, option.dest, json.loads(value))
parser.add_option('--build-properties', action='callback',
callback=convert_json, type='string', default={},
help='build properties in JSON format')
parser.add_option('--factory-properties', action='callback',
callback=convert_json, type='string', default={},
help='factory properties in JSON format')
parser.add_option('--slave-properties', action='callback',
callback=convert_json, type='string', default={},
help='Properties set by slave script in JSON format')
parser = bb_utils.GetParser()
parser.add_option('--experimental', action='store_true',
help='Run experiemental tests')
parser.add_option('-f', '--test-filter', metavar='<filter>', default=[],
@ -344,18 +300,12 @@ def main(argv):
help='Push script to device which restarts adbd on disconnections.')
options, args = parser.parse_args(argv[1:])
def ParserError(msg):
"""We avoid parser.error because it calls sys.exit."""
parser.print_help()
print >> sys.stderr, '\nERROR:', msg
return 1
if args:
return ParserError('Unused args %s' % args)
return sys.exit('Unused args %s' % args)
unknown_tests = set(options.test_filter) - VALID_TESTS
if unknown_tests:
return ParserError('Unknown tests %s' % list(unknown_tests))
return sys.exit('Unknown tests %s' % list(unknown_tests))
setattr(options, 'target', options.factory_properties.get('target', 'Debug'))

137
android/buildbot/bb_host_steps.py Executable file
Просмотреть файл

@ -0,0 +1,137 @@
#!/usr/bin/env python
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import json
import os
import sys
import bb_utils
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from pylib import buildbot_report
from pylib import constants
SLAVE_SCRIPTS_DIR = os.path.join(bb_utils.BB_BUILD_DIR, 'scripts', 'slave')
VALID_HOST_TESTS = set(['check_webview_licenses', 'findbugs'])
EXPERIMENTAL_TARGETS = ['android_experimental']
# Short hand for RunCmd which is used extensively in this file.
RunCmd = bb_utils.RunCmd
def SrcPath(*path):
return os.path.join(constants.DIR_SOURCE_ROOT, *path)
def CheckWebViewLicenses():
buildbot_report.PrintNamedStep('Check licenses for WebView')
RunCmd([SrcPath('android_webview', 'tools', 'webview_licenses.py'), 'scan'],
warning_code=1)
def RunHooks():
buildbot_report.PrintNamedStep('runhooks')
RunCmd(['gclient', 'runhooks'], halt_on_failure=True)
def Compile(build_type, args, experimental=False):
cmd = [os.path.join(SLAVE_SCRIPTS_DIR, 'compile.py'),
'--build-tool=ninja',
'--compiler=goma',
'--target=%s' % build_type,
'--goma-dir=%s' % os.path.join(bb_utils.BB_BUILD_DIR, 'goma')]
if experimental:
for compile_target in args:
buildbot_report.PrintNamedStep('Experimental Compile %s' % compile_target)
RunCmd(cmd + ['--build-args=%s' % compile_target], flunk_on_failure=False)
else:
buildbot_report.PrintNamedStep('compile')
RunCmd(cmd + ['--build-args=%s' % ' '.join(args)], halt_on_failure=True)
def ZipBuild(factory_properties, build_properties):
buildbot_report.PrintNamedStep('Zip build')
RunCmd([os.path.join(SLAVE_SCRIPTS_DIR, 'zip_build.py'),
'--src-dir', constants.DIR_SOURCE_ROOT,
'--build-dir', SrcPath('out'),
'--exclude-files', 'lib.target,gen,android_webview,jingle_unittests',
'--factory-properties', json.dumps(factory_properties),
'--build-properties', json.dumps(build_properties)])
def ExtractBuild(factory_properties, build_properties):
buildbot_report.PrintNamedStep('Download and extract build')
RunCmd([os.path.join(SLAVE_SCRIPTS_DIR, 'extract_build.py'),
'--build-dir', SrcPath('build'),
'--build-output-dir', SrcPath('out'),
'--factory-properties', json.dumps(factory_properties),
'--build-properties', json.dumps(build_properties)],
warning_code=1)
def FindBugs(is_release):
buildbot_report.PrintNamedStep('findbugs')
build_type = []
if is_release:
build_type = ['--release-build']
RunCmd([SrcPath('build', 'android', 'findbugs_diff.py')] + build_type)
RunCmd([SrcPath(
'tools', 'android', 'findbugs_plugin', 'test',
'run_findbugs_plugin_tests.py')] + build_type)
def UpdateClang():
RunCmd([SrcPath('tools', 'clang', 'scripts', 'update.sh')])
def main(argv):
parser = bb_utils.GetParser()
parser.add_option('--host-tests', help='Comma separated list of host tests.')
parser.add_option('--build-args', default='All',
help='Comma separated list of build targets.')
parser.add_option('--compile', action='store_true',
help='Indicate whether a compile step should be run.')
parser.add_option('--experimental', action='store_true',
help='Indicate whether to compile experimental targets.')
parser.add_option('--zip-build', action='store_true',
help='Indicate whether the build should be zipped.')
parser.add_option('--extract-build', action='store_true',
help='Indicate whether a build should be downloaded.')
parser.add_option('--update-clang', action='store_true',
help='Download or build the ASan runtime library.')
options, args = parser.parse_args(argv[1:])
if args:
return sys.exit('Unused args %s' % args)
host_tests = []
if options.host_tests:
host_tests = options.host_tests.split(',')
unknown_tests = set(host_tests) - VALID_HOST_TESTS
if unknown_tests:
return sys.exit('Unknown host tests %s' % list(unknown_tests))
build_type = options.factory_properties.get('target', 'Debug')
if options.compile:
if 'check_webview_licenses' in host_tests:
CheckWebViewLicenses()
RunHooks()
Compile(build_type, options.build_args.split(','))
if options.experimental:
Compile(build_type, EXPERIMENTAL_TARGETS, True)
if 'findbugs' in host_tests:
FindBugs(build_type == 'Release')
if options.zip_build:
ZipBuild(options.factory_properties, options.build_properties)
if options.update_clang:
UpdateClang()
if options.extract_build:
ExtractBuild(options.factory_properties, options.build_properties)
if __name__ == '__main__':
sys.exit(main(sys.argv))

Просмотреть файл

@ -13,6 +13,8 @@ import pipes
import subprocess
import sys
import bb_utils
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from pylib import buildbot_report
@ -22,11 +24,13 @@ CHROME_SRC = os.path.abspath(
GLOBAL_SLAVE_PROPS = {}
BotConfig = collections.namedtuple(
'BotConfig', ['bot_id', 'bash_funs', 'test_obj', 'slave_props'])
'BotConfig', ['bot_id', 'host_opts', 'test_obj', 'slave_props'])
TestConfig = collections.namedtuple('Tests', ['tests', 'extra_args'])
Command = collections.namedtuple(
'Command', ['step_name', 'command', 'testing_cmd'])
CommandToString = bb_utils.CommandToString
def GetCommands(options, bot_config):
"""Get a formatted list of commands.
@ -41,26 +45,28 @@ def GetCommands(options, bot_config):
if bot_config.slave_props:
slave_props.update(bot_config.slave_props)
slave_properties = json.dumps(slave_props)
property_args = [
'--factory-properties=%s' % json.dumps(options.factory_properties),
'--build-properties=%s' % json.dumps(options.build_properties),
'--slave-properties=%s' % json.dumps(slave_props)]
'--slave-properties=%s' % slave_properties]
commands = []
def WrapWithBash(command):
"""Wrap a bash command string with envsetup scripts."""
return ['bash', '-exc', '; '.join([
'. build/android/buildbot/buildbot_functions.sh',
'bb_baseline_setup %s %s' % (
CHROME_SRC,
' '.join(map(pipes.quote, property_args))),
'bb_baseline_setup %s --slave-properties=%s' % (
CHROME_SRC, pipes.quote(slave_properties)),
command])
]
if bot_config.bash_funs:
# bash_funs command does not have a testing mode.
commands.append(
Command(None, WrapWithBash('; '.join(bot_config.bash_funs)), None))
if bot_config.host_opts:
host_cmd = (['build/android/buildbot/bb_host_steps.py'] +
bot_config.host_opts + property_args)
commands.append(Command(
'Host steps',
WrapWithBash(' '.join(map(pipes.quote, host_cmd))), host_cmd))
test_obj = bot_config.test_obj
if test_obj:
@ -78,9 +84,10 @@ def GetCommands(options, bot_config):
def GetBotStepMap():
compile_step = ['bb_compile']
std_build_steps = ['bb_compile', 'bb_zip_build']
std_test_steps = ['bb_extract_build']
compile_opt = ['--compile']
std_host_tests = ['--host-tests=check_webview_licenses,findbugs']
std_build_opts = ['--compile', '--zip-build']
std_test_opts = ['--extract-build']
std_tests = ['ui', 'unit']
flakiness_server = '--upload-to-flakiness-server'
extra_gyp = 'extra_gyp_defines'
@ -93,39 +100,35 @@ def GetBotStepMap():
bot_configs = [
# Main builders
B('main-builder-dbg',
['bb_check_webview_licenses', 'bb_compile', 'bb_run_findbugs',
'bb_zip_build']),
B('main-builder-rel', ['bb_compile', 'bb_zip_build']),
B('main-clang-builder', compile_step, slave_props={extra_gyp: 'clang=1'}),
B('main-clobber', compile_step),
B('main-tests', std_test_steps, T(std_tests, [flakiness_server])),
B('main-builder-dbg', std_build_opts + std_host_tests),
B('main-builder-rel', std_build_opts),
B('main-clang-builder', compile_opt, slave_props={extra_gyp: 'clang=1'}),
B('main-clobber', compile_opt),
B('main-tests', std_test_opts, T(std_tests, [flakiness_server])),
# Other waterfalls
B('asan-builder-tests', compile_step + ['bb_asan_tests_setup'],
B('asan-builder-tests', compile_opt + ['--update-clang'],
T(std_tests, ['--asan']), {extra_gyp: 'asan=1'}),
B('chromedriver-fyi-tests-dbg', std_test_steps,
B('chromedriver-fyi-tests-dbg', std_test_opts,
T(['chromedriver'], ['--install=ChromiumTestShell'])),
B('fyi-builder-dbg',
['bb_check_webview_licenses', 'bb_compile', 'bb_compile_experimental',
'bb_run_findbugs', 'bb_zip_build']),
B('fyi-builder-rel',
['bb_compile', 'bb_compile_experimental', 'bb_zip_build']),
B('fyi-tests-dbg-ics-gn', ['bb_compile', 'bb_compile_experimental'],
std_build_opts + std_host_tests + ['--experimental']),
B('fyi-builder-rel', std_build_opts + ['--experimental']),
B('fyi-tests-dbg-ics-gn', compile_opt + [ '--experimental'],
T(std_tests, ['--experimental', flakiness_server])),
B('fyi-tests', std_test_steps,
B('fyi-tests', std_test_opts,
T(std_tests, ['--experimental', flakiness_server])),
B('fyi-component-builder-tests-dbg', compile_step,
B('fyi-component-builder-tests-dbg', compile_opt,
T(std_tests, ['--experimental', flakiness_server]),
{extra_gyp: 'component=shared_library'}),
B('perf-tests-rel', std_test_steps, T([], ['--install=ContentShell'])),
B('webkit-latest-webkit-tests', std_test_steps,
B('perf-tests-rel', std_test_opts, T([], ['--install=ContentShell'])),
B('webkit-latest-webkit-tests', std_test_opts,
T(['webkit_layout', 'webkit'])),
B('webkit-latest-contentshell', compile_step, T(['webkit_layout'])),
B('builder-unit-tests', compile_step, T(['unit'])),
B('webkit-latest-contentshell', compile_opt, T(['webkit_layout'])),
B('builder-unit-tests', compile_opt, T(['unit'])),
# Generic builder config (for substring match).
B('builder', std_build_steps),
B('builder', std_build_opts),
]
bot_map = dict((config.bot_id, config) for config in bot_configs)
@ -197,10 +200,6 @@ def main(argv):
print 'Using config:', bot_config
def CommandToString(command):
"""Returns quoted command that can be run in bash shell."""
return ' '.join(map(pipes.quote, command))
command_objs = GetCommands(options, bot_config)
for command_obj in command_objs:
print 'Will run:', CommandToString(command_obj.command)

Просмотреть файл

@ -0,0 +1,75 @@
# Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import json
import optparse
import os
import pipes
import subprocess
import sys
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from pylib import buildbot_report
from pylib import constants
TESTING = 'BUILDBOT_TESTING' in os.environ
BB_BUILD_DIR = os.path.abspath(
os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir,
os.pardir, os.pardir, os.pardir, os.pardir))
def CommandToString(command):
"""Returns quoted command that can be run in bash shell."""
return ' '.join(map(pipes.quote, command))
def SpawnCmd(command):
"""Spawn a process without waiting for termination."""
print '>', CommandToString(command)
sys.stdout.flush()
if TESTING:
class MockPopen(object):
@staticmethod
def wait():
return 0
return MockPopen()
return subprocess.Popen(command, cwd=constants.DIR_SOURCE_ROOT)
def RunCmd(command, flunk_on_failure=True, halt_on_failure=False,
warning_code=88):
"""Run a command relative to the chrome source root."""
code = SpawnCmd(command).wait()
print '<', CommandToString(command)
if code != 0:
print 'ERROR: process exited with code %d' % code
if code != warning_code and flunk_on_failure:
buildbot_report.PrintError()
else:
buildbot_report.PrintWarning()
# Allow steps to have both halting (i.e. 1) and non-halting exit codes.
if code != warning_code and halt_on_failure:
raise OSError()
return code
def GetParser():
def ConvertJson(option, _, value, parser):
setattr(parser.values, option.dest, json.loads(value))
parser = optparse.OptionParser()
parser.add_option('--build-properties', action='callback',
callback=ConvertJson, type='string', default={},
help='build properties in JSON format')
parser.add_option('--factory-properties', action='callback',
callback=ConvertJson, type='string', default={},
help='factory properties in JSON format')
parser.add_option('--slave-properties', action='callback',
callback=ConvertJson, type='string', default={},
help='Properties set by slave script in JSON format')
return parser

Просмотреть файл

@ -44,7 +44,6 @@ function bb_baseline_setup {
shift
cd $SRC_ROOT
echo "@@@BUILD_STEP Environment setup@@@"
bb_parse_args "$@"
export GYP_GENERATORS=ninja
@ -84,142 +83,6 @@ function bb_baseline_setup {
fi
}
function bb_asan_tests_setup {
# Download or build the ASan runtime library.
${SRC_ROOT}/tools/clang/scripts/update.sh
}
# Setup goma. Used internally to buildbot_functions.sh.
function bb_setup_goma_internal {
echo "Killing old goma processes"
${GOMA_DIR}/goma_ctl.sh stop || true
killall -9 compiler_proxy || true
echo "Starting goma"
export GOMA_API_KEY_FILE=${GOMA_DIR}/goma.key
${GOMA_DIR}/goma_ctl.sh start
trap bb_stop_goma_internal SIGHUP SIGINT SIGTERM
}
# Stop goma.
function bb_stop_goma_internal {
echo "Stopping goma"
${GOMA_DIR}/goma_ctl.sh stop
}
# Build using ninja.
function bb_goma_ninja {
echo "Using ninja to build."
local TARGET=$1
bb_setup_goma_internal
ninja -C out/$BUILDTYPE -j120 -l20 $TARGET
bb_stop_goma_internal
}
# Compile step
function bb_compile {
# This must be named 'compile' for CQ.
echo "@@@BUILD_STEP compile@@@"
gclient runhooks
bb_goma_ninja All
}
# Experimental compile step; does not turn the tree red if it fails.
function bb_compile_experimental {
# Linking DumpRenderTree appears to hang forever?
EXPERIMENTAL_TARGETS="android_experimental"
for target in ${EXPERIMENTAL_TARGETS} ; do
echo "@@@BUILD_STEP Experimental Compile $target @@@"
set +e
bb_goma_ninja "${target}"
if [ $? -ne 0 ] ; then
echo "@@@STEP_WARNINGS@@@"
fi
set -e
done
}
# Run findbugs.
function bb_run_findbugs {
echo "@@@BUILD_STEP findbugs@@@"
if [[ $BUILDTYPE = Release ]]; then
local BUILDFLAG="--release-build"
fi
bb_run_step build/android/findbugs_diff.py $BUILDFLAG
bb_run_step tools/android/findbugs_plugin/test/run_findbugs_plugin_tests.py \
$BUILDFLAG
}
# Run a buildbot step and handle failure (failure will not halt build).
function bb_run_step {
(
set +e
"$@"
if [[ $? != 0 ]]; then
echo "@@@STEP_FAILURE@@@"
fi
)
}
# Zip and archive a build.
function bb_zip_build {
echo "@@@BUILD_STEP Zip build@@@"
python ../../../../scripts/slave/zip_build.py \
--src-dir "$SRC_ROOT" \
--build-dir "out" \
--exclude-files "lib.target,gen,android_webview,jingle_unittests" \
--factory-properties "$FACTORY_PROPERTIES" \
--build-properties "$BUILD_PROPERTIES"
}
# Download and extract a build.
function bb_extract_build {
echo "@@@BUILD_STEP Download and extract build@@@"
if [[ -z $FACTORY_PROPERTIES || -z $BUILD_PROPERTIES ]]; then
return 1
fi
# When extract_build.py downloads an unversioned build it
# issues a warning by exiting with large numbered return code
# When it fails to download it build, it exits with return
# code 1. We disable halt on error mode and return normally
# unless the python tool returns 1.
(
set +e
python ../../../../scripts/slave/extract_build.py \
--build-dir "$SRC_ROOT/build" \
--build-output-dir "../out" \
--factory-properties "$FACTORY_PROPERTIES" \
--build-properties "$BUILD_PROPERTIES"
local extract_exit_code=$?
if (( $extract_exit_code > 1 )); then
echo "@@@STEP_WARNINGS@@@"
return
fi
return $extract_exit_code
)
}
# Runs the license checker for the WebView build.
# License checker may return error code 1 meaning that
# there are non-fatal problems (warnings). Everything
# above 1 is considered to be a show-stopper.
function bb_check_webview_licenses {
echo "@@@BUILD_STEP Check licenses for WebView@@@"
(
set +e
cd "${SRC_ROOT}"
python android_webview/tools/webview_licenses.py scan
local licenses_exit_code=$?
if [[ $licenses_exit_code -eq 1 ]]; then
echo "@@@STEP_WARNINGS@@@"
elif [[ $licenses_exit_code -gt 1 ]]; then
echo "@@@STEP_FAILURE@@@"
fi
return 0
)
}
# Retrieve a packed json property using python
function bb_get_json_prop {
local JSON="$1"