1# Copyright (C) 2012 Google Inc. All rights reserved. 2# 3# Redistribution and use in source and binary forms, with or without 4# modification, are permitted provided that the following conditions are 5# met: 6# 7# * Redistributions of source code must retain the above copyright 8# notice, this list of conditions and the following disclaimer. 9# * Redistributions in binary form must reproduce the above 10# copyright notice, this list of conditions and the following disclaimer 11# in the documentation and/or other materials provided with the 12# distribution. 13# * Neither the name of Google Inc. nor the names of its 14# contributors may be used to endorse or promote products derived from 15# this software without specific prior written permission. 16# 17# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29import logging 30import optparse 31import signal 32import traceback 33 34from webkitpy.common.host import Host 35from webkitpy.layout_tests.models import test_expectations 36from webkitpy.layout_tests.port import platform_options 37 38 39# This mirrors what the shell normally does. 40INTERRUPTED_EXIT_STATUS = signal.SIGINT + 128 41 42# This is a randomly chosen exit code that can be tested against to 43# indicate that an unexpected exception occurred. 44EXCEPTIONAL_EXIT_STATUS = 254 45 46_log = logging.getLogger(__name__) 47 48 49def lint(host, options): 50 # FIXME: Remove this when we remove the --chromium flag (crbug.com/245504). 51 if options.platform == 'chromium': 52 options.platform = None 53 54 ports_to_lint = [host.port_factory.get(name) for name in host.port_factory.all_port_names(options.platform)] 55 files_linted = set() 56 lint_failed = False 57 58 for port_to_lint in ports_to_lint: 59 expectations_dict = port_to_lint.expectations_dict() 60 61 for expectations_file in expectations_dict.keys(): 62 if expectations_file in files_linted: 63 continue 64 65 try: 66 test_expectations.TestExpectations(port_to_lint, 67 expectations_dict={expectations_file: expectations_dict[expectations_file]}, 68 is_lint_mode=True) 69 except test_expectations.ParseError as e: 70 lint_failed = True 71 _log.error('') 72 for warning in e.warnings: 73 _log.error(warning) 74 _log.error('') 75 files_linted.add(expectations_file) 76 return lint_failed 77 78 79def check_virtual_test_suites(host, options): 80 port = host.port_factory.get(options=options) 81 fs = host.filesystem 82 layout_tests_dir = port.layout_tests_dir() 83 virtual_suites = port.virtual_test_suites() 84 85 check_failed = False 86 for suite in virtual_suites: 87 comps = [layout_tests_dir] + suite.name.split('/') + ['README.txt'] 88 path_to_readme = fs.join(*comps) 89 if not fs.exists(path_to_readme): 90 _log.error('LayoutTests/%s/README.txt is missing (each virtual suite must have one).' % suite.name) 91 check_failed = True 92 if check_failed: 93 _log.error('') 94 return check_failed 95 96 97def set_up_logging(logging_stream): 98 logger = logging.getLogger() 99 logger.setLevel(logging.INFO) 100 handler = logging.StreamHandler(logging_stream) 101 logger.addHandler(handler) 102 return (logger, handler) 103 104 105def tear_down_logging(logger, handler): 106 logger.removeHandler(handler) 107 108 109def run_checks(host, options, logging_stream): 110 logger, handler = set_up_logging(logging_stream) 111 try: 112 lint_failed = lint(host, options) 113 check_failed = check_virtual_test_suites(host, options) 114 if lint_failed or check_failed: 115 _log.error('Lint failed.') 116 return 1 117 else: 118 _log.info('Lint succeeded.') 119 return 0 120 finally: 121 logger.removeHandler(handler) 122 123 124def main(argv, _, stderr): 125 parser = optparse.OptionParser(option_list=platform_options(use_globs=True)) 126 options, _ = parser.parse_args(argv) 127 128 if options.platform and 'test' in options.platform: 129 # It's a bit lame to import mocks into real code, but this allows the user 130 # to run tests against the test platform interactively, which is useful for 131 # debugging test failures. 132 from webkitpy.common.host_mock import MockHost 133 host = MockHost() 134 else: 135 host = Host() 136 137 try: 138 exit_status = run_checks(host, options, stderr) 139 except KeyboardInterrupt: 140 exit_status = INTERRUPTED_EXIT_STATUS 141 except Exception as e: 142 print >> stderr, '\n%s raised: %s' % (e.__class__.__name__, str(e)) 143 traceback.print_exc(file=stderr) 144 exit_status = EXCEPTIONAL_EXIT_STATUS 145 146 return exit_status 147