15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Copyright (c) 2010 Google Inc. All rights reserved. 25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# 35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# Redistribution and use in source and binary forms, with or without 45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# modification, are permitted provided that the following conditions are 55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# met: 65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# 75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# * Redistributions of source code must retain the above copyright 85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# notice, this list of conditions and the following disclaimer. 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# * Redistributions in binary form must reproduce the above 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# copyright notice, this list of conditions and the following disclaimer 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# in the documentation and/or other materials provided with the 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# distribution. 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# * Neither the name of Google Inc. nor the names of its 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# contributors may be used to endorse or promote products derived from 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# this software without specific prior written permission. 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# 175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles)# (INCLUDING NEGLIGENCE OR/ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 29c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)import Queue 305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import json 315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import logging 325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import optparse 3383750176c3ee2cea66c8a9751271026a5901be3aBen Murdochimport re 345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)import sys 35c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)import threading 3683750176c3ee2cea66c8a9751271026a5901be3aBen Murdochimport time 37e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)import traceback 38e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)import urllib 3983750176c3ee2cea66c8a9751271026a5901be3aBen Murdochimport urllib2 405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from webkitpy.common.checkout.baselineoptimizer import BaselineOptimizer 4253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)from webkitpy.common.memoized import memoized 435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from webkitpy.common.system.executive import ScriptError 445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from webkitpy.layout_tests.controllers.test_result_writer import TestResultWriter 455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from webkitpy.layout_tests.models import test_failures 46e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)from webkitpy.layout_tests.models.test_expectations import TestExpectations, BASELINE_SUFFIX_LIST, SKIP 475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from webkitpy.layout_tests.port import builders 485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from webkitpy.layout_tests.port import factory 495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand 505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)_log = logging.getLogger(__name__) 535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)# FIXME: Should TestResultWriter know how to compute this string? 565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)def _baseline_name(fs, test_name, suffix): 575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return fs.splitext(test_name)[0] + TestResultWriter.FILENAME_SUFFIX_EXPECTED + "." + suffix 585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class AbstractRebaseliningCommand(AbstractDeclarativeCommand): 61926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) # not overriding execute() - pylint: disable=W0223 625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) no_optimize_option = optparse.make_option('--no-optimize', dest='optimize', action='store_false', default=True, 645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) help=('Do not optimize/de-dup the expectations after rebaselining (default is to de-dup automatically). ' 655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 'You can use "webkit-patch optimize-baselines" to optimize separately.')) 665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) platform_options = factory.platform_options(use_globs=True) 685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) results_directory_option = optparse.make_option("--results-directory", help="Local results directory to use") 705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) suffixes_option = optparse.make_option("--suffixes", default=','.join(BASELINE_SUFFIX_LIST), action="store", 725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) help="Comma-separated-list of file types to rebaseline") 735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def __init__(self, options=None): 755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) super(AbstractRebaseliningCommand, self).__init__(options=options) 765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self._baseline_suffix_list = BASELINE_SUFFIX_LIST 77f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) self._scm_changes = {'add': [], 'delete': [], 'remove-lines': []} 78f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) 79f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) def _add_to_scm_later(self, path): 80f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) self._scm_changes['add'].append(path) 81f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) 82f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) def _delete_from_scm_later(self, path): 83f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) self._scm_changes['delete'].append(path) 845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 86e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdochclass BaseInternalRebaselineCommand(AbstractRebaseliningCommand): 875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def __init__(self): 88e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch super(BaseInternalRebaselineCommand, self).__init__(options=[ 895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self.results_directory_option, 905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self.suffixes_option, 915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) optparse.make_option("--builder", help="Builder to pull new baselines from"), 925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) optparse.make_option("--test", help="Test to rebaseline"), 935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ]) 945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def _baseline_directory(self, builder_name): 965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) port = self._tool.port_factory.get_from_builder_name(builder_name) 975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) override_dir = builders.rebaseline_override_dir(builder_name) 985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if override_dir: 995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return self._tool.filesystem.join(port.layout_tests_dir(), 'platform', override_dir) 1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return port.baseline_version_dir() 1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 102e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch def _test_root(self, test_name): 103e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch return self._tool.filesystem.splitext(test_name)[0] 104e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch 105e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch def _file_name_for_actual_result(self, test_name, suffix): 106e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch return "%s-actual.%s" % (self._test_root(test_name), suffix) 107e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch 108e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch def _file_name_for_expected_result(self, test_name, suffix): 109e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch return "%s-expected.%s" % (self._test_root(test_name), suffix) 110e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch 111e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch 112e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdochclass CopyExistingBaselinesInternal(BaseInternalRebaselineCommand): 113e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch name = "copy-existing-baselines-internal" 114e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch help_text = "Copy existing baselines down one level in the baseline order to ensure new baselines don't break existing passing platforms." 115e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch 11653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) @memoized 11753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) def _immediate_predecessors_in_fallback(self, path_to_rebaseline): 11853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) port_names = self._tool.port_factory.all_port_names() 11953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) immediate_predecessors_in_fallback = [] 12053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) for port_name in port_names: 12153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) port = self._tool.port_factory.get(port_name) 12253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) if not port.buildbot_archives_baselines(): 12353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) continue 12453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) baseline_search_path = port.baseline_search_path() 12553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) try: 12653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) index = baseline_search_path.index(path_to_rebaseline) 12753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) if index: 12853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) immediate_predecessors_in_fallback.append(self._tool.filesystem.basename(baseline_search_path[index - 1])) 12953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) except ValueError: 13053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) # index throw's a ValueError if the item isn't in the list. 13153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) pass 13253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) return immediate_predecessors_in_fallback 13353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) 134521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) def _port_for_primary_baseline(self, baseline): 135521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) for port in [self._tool.port_factory.get(port_name) for port_name in self._tool.port_factory.all_port_names()]: 136521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) if self._tool.filesystem.basename(port.baseline_version_dir()) == baseline: 137521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) return port 138521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) raise Exception("Failed to find port for primary baseline %s." % baseline) 139521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) 140e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch def _copy_existing_baseline(self, builder_name, test_name, suffix): 141e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch baseline_directory = self._baseline_directory(builder_name) 142e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch ports = [self._port_for_primary_baseline(baseline) for baseline in self._immediate_predecessors_in_fallback(baseline_directory)] 143e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch 1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) old_baselines = [] 1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) new_baselines = [] 1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) # Need to gather all the baseline paths before modifying the filesystem since 1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) # the modifications can affect the results of port.expected_filename. 149e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch for port in ports: 1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) old_baseline = port.expected_filename(test_name, "." + suffix) 1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if not self._tool.filesystem.exists(old_baseline): 1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) _log.debug("No existing baseline for %s." % test_name) 1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) continue 1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) new_baseline = self._tool.filesystem.join(port.baseline_path(), self._file_name_for_expected_result(test_name, suffix)) 1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if self._tool.filesystem.exists(new_baseline): 1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) _log.debug("Existing baseline at %s, not copying over it." % new_baseline) 1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) continue 1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 160e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) expectations = TestExpectations(port, [test_name]) 161e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) if SKIP in expectations.get_expectations(test_name): 162e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) _log.debug("%s is skipped on %s." % (test_name, port.name())) 163e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) continue 164e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) 1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) old_baselines.append(old_baseline) 1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) new_baselines.append(new_baseline) 1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for i in range(len(old_baselines)): 1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) old_baseline = old_baselines[i] 1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) new_baseline = new_baselines[i] 1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) _log.debug("Copying baseline from %s to %s." % (old_baseline, new_baseline)) 1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self._tool.filesystem.maybe_make_directory(self._tool.filesystem.dirname(new_baseline)) 1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self._tool.filesystem.copyfile(old_baseline, new_baseline) 1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if not self._tool.scm().exists(new_baseline): 176f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) self._add_to_scm_later(new_baseline) 1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 178e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch def execute(self, options, args, tool): 179e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch for suffix in options.suffixes.split(','): 180e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch self._copy_existing_baseline(options.builder, options.test, suffix) 181e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch print json.dumps(self._scm_changes) 182e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch 183e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch 184e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdochclass RebaselineTest(BaseInternalRebaselineCommand): 185e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch name = "rebaseline-test-internal" 186e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch help_text = "Rebaseline a single test from a buildbot. Only intended for use by other webkit-patch commands." 187e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch 188e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch def _results_url(self, builder_name): 189e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch return self._tool.buildbot_for_builder_name(builder_name).builder_with_name(builder_name).latest_layout_test_results_url() 190e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch 19153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) def _save_baseline(self, data, target_baseline, baseline_directory, test_name, suffix): 1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if not data: 19353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) _log.debug("No baseline data to save.") 1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 19553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) 1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) filesystem = self._tool.filesystem 1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) filesystem.maybe_make_directory(filesystem.dirname(target_baseline)) 1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) filesystem.write_binary_file(target_baseline, data) 1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if not self._tool.scm().exists(target_baseline): 200f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) self._add_to_scm_later(target_baseline) 2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 202e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch def _rebaseline_test(self, builder_name, test_name, suffix, results_url): 2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) baseline_directory = self._baseline_directory(builder_name) 2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) source_baseline = "%s/%s" % (results_url, self._file_name_for_actual_result(test_name, suffix)) 2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) target_baseline = self._tool.filesystem.join(baseline_directory, self._file_name_for_expected_result(test_name, suffix)) 2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) _log.debug("Retrieving %s." % source_baseline) 20953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) self._save_baseline(self._tool.web.get_binary(source_baseline, convert_404_to_None=True), target_baseline, baseline_directory, test_name, suffix) 2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def _rebaseline_test_and_update_expectations(self, options): 21253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) port = self._tool.port_factory.get_from_builder_name(options.builder) 21353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) if (port.reference_files(options.test)): 21453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) _log.warning("Cannot rebaseline reftest: %s", options.test) 21553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) return 21653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) 2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if options.results_directory: 2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) results_url = 'file://' + options.results_directory 2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else: 2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) results_url = self._results_url(options.builder) 2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self._baseline_suffix_list = options.suffixes.split(',') 22281a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) 2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for suffix in self._baseline_suffix_list: 224e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch self._rebaseline_test(options.builder, options.test, suffix, results_url) 22553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) self._scm_changes['remove-lines'].append({'builder': options.builder, 'test': options.test}) 2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def execute(self, options, args, tool): 2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self._rebaseline_test_and_update_expectations(options) 2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) print json.dumps(self._scm_changes) 2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class OptimizeBaselines(AbstractRebaseliningCommand): 2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) name = "optimize-baselines" 2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) help_text = "Reshuffles the baselines for the given tests to use as litte space on disk as possible." 2351e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) show_in_main_help = True 2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) argument_names = "TEST_NAMES" 2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def __init__(self): 239f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) super(OptimizeBaselines, self).__init__(options=[ 240f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) self.suffixes_option, 241f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) optparse.make_option('--no-modify-scm', action='store_true', default=False, help='Dump SCM commands as JSON instead of '), 242f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) ] + self.platform_options) 2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def _optimize_baseline(self, optimizer, test_name): 2457242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci files_to_delete = [] 2467242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci files_to_add = [] 2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for suffix in self._baseline_suffix_list: 2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) baseline_name = _baseline_name(self._tool.filesystem, test_name, suffix) 2497242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci succeeded, more_files_to_delete, more_files_to_add = optimizer.optimize(baseline_name) 250f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) if not succeeded: 2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) print "Heuristics failed to optimize %s" % baseline_name 2527242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci files_to_delete.extend(more_files_to_delete) 2537242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci files_to_add.extend(more_files_to_add) 2547242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci return files_to_delete, files_to_add 2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def execute(self, options, args, tool): 2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self._baseline_suffix_list = options.suffixes.split(',') 2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) port_names = tool.port_factory.all_port_names(options.platform) 2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if not port_names: 2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) print "No port names match '%s'" % options.platform 2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) port = tool.port_factory.get(port_names[0]) 2637242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci optimizer = BaselineOptimizer(tool, port, port_names, skip_scm_commands=options.no_modify_scm) 2647242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci tests = port.tests(args) 2657242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci for test_name in tests: 266f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) files_to_delete, files_to_add = self._optimize_baseline(optimizer, test_name) 267f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) for path in files_to_delete: 268f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) self._delete_from_scm_later(path) 269f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) for path in files_to_add: 270f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) self._add_to_scm_later(path) 271f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) 272f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) print json.dumps(self._scm_changes) 2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class AnalyzeBaselines(AbstractRebaseliningCommand): 2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) name = "analyze-baselines" 2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) help_text = "Analyzes the baselines for the given tests and prints results that are identical." 2781e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) show_in_main_help = True 2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) argument_names = "TEST_NAMES" 2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def __init__(self): 2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) super(AnalyzeBaselines, self).__init__(options=[ 2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self.suffixes_option, 2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) optparse.make_option('--missing', action='store_true', default=False, help='show missing baselines as well'), 2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ] + self.platform_options) 2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self._optimizer_class = BaselineOptimizer # overridable for testing 2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self._baseline_optimizer = None 2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self._port = None 2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def _write(self, msg): 2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) print msg 2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def _analyze_baseline(self, options, test_name): 2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for suffix in self._baseline_suffix_list: 2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) baseline_name = _baseline_name(self._tool.filesystem, test_name, suffix) 2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) results_by_directory = self._baseline_optimizer.read_results_by_directory(baseline_name) 2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if results_by_directory: 2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self._write("%s:" % baseline_name) 2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self._baseline_optimizer.write_by_directory(results_by_directory, self._write, " ") 3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) elif options.missing: 3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self._write("%s: (no baselines found)" % baseline_name) 3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def execute(self, options, args, tool): 3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self._baseline_suffix_list = options.suffixes.split(',') 3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) port_names = tool.port_factory.all_port_names(options.platform) 3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if not port_names: 3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) print "No port names match '%s'" % options.platform 3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self._port = tool.port_factory.get(port_names[0]) 3107242dc3dbeb210b5e876a3c42d1ec1a667fc621aPrimiano Tucci self._baseline_optimizer = self._optimizer_class(tool, self._port, port_names, skip_scm_commands=False) 3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for test_name in self._port.tests(args): 3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self._analyze_baseline(options, test_name) 3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class AbstractParallelRebaselineCommand(AbstractRebaseliningCommand): 316926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) # not overriding execute() - pylint: disable=W0223 3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3183c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch def __init__(self, options=None): 3193c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch super(AbstractParallelRebaselineCommand, self).__init__(options=options) 3203c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch self._builder_data = {} 3213c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch 3223c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch def builder_data(self): 3233c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch if not self._builder_data: 3243c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch for builder_name in self._release_builders(): 3253c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch builder = self._tool.buildbot_for_builder_name(builder_name).builder_with_name(builder_name) 3263c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch self._builder_data[builder_name] = builder.latest_layout_test_results() 3273c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch return self._builder_data 3283c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch 329e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch # The release builders cycle much faster than the debug ones and cover all the platforms. 330e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch def _release_builders(self): 331e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch release_builders = [] 332e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch for builder_name in builders.all_builder_names(): 333d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) if builder_name.find('ASAN') != -1: 334d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) continue 335e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch port = self._tool.port_factory.get_from_builder_name(builder_name) 336e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch if port.test_configuration().build_type == 'release': 337e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch release_builders.append(builder_name) 338e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch return release_builders 339e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch 3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def _run_webkit_patch(self, args, verbose): 3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) try: 3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) verbose_args = ['--verbose'] if verbose else [] 3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) stderr = self._tool.executive.run_command([self._tool.path()] + verbose_args + args, cwd=self._tool.scm().checkout_root, return_stderr=True) 3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for line in stderr.splitlines(): 34583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch _log.warning(line) 3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) except ScriptError, e: 3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) _log.error(e) 3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def _builders_to_fetch_from(self, builders_to_check): 3505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) # This routine returns the subset of builders that will cover all of the baseline search paths 3515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) # used in the input list. In particular, if the input list contains both Release and Debug 3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) # versions of a configuration, we *only* return the Release version (since we don't save 3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) # debug versions of baselines). 3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) release_builders = set() 3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) debug_builders = set() 3565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) builders_to_fallback_paths = {} 3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for builder in builders_to_check: 3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) port = self._tool.port_factory.get_from_builder_name(builder) 359e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch if port.test_configuration().build_type == 'release': 3605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) release_builders.add(builder) 3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else: 3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) debug_builders.add(builder) 3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for builder in list(release_builders) + list(debug_builders): 3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) port = self._tool.port_factory.get_from_builder_name(builder) 3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) fallback_path = port.baseline_search_path() 3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if fallback_path not in builders_to_fallback_paths.values(): 3675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) builders_to_fallback_paths[builder] = fallback_path 3685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return builders_to_fallback_paths.keys() 3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 37081a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) def _rebaseline_commands(self, test_prefix_list, options): 3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) path_to_webkit_patch = self._tool.path() 3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) cwd = self._tool.scm().checkout_root 373e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch copy_baseline_commands = [] 374e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch rebaseline_commands = [] 375f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) lines_to_remove = {} 37681a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) port = self._tool.port_factory.get() 37781a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) 37881a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) for test_prefix in test_prefix_list: 37981a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) for test in port.tests([test_prefix]): 38081a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) for builder in self._builders_to_fetch_from(test_prefix_list[test_prefix]): 3813c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch actual_failures_suffixes = self._suffixes_for_actual_failures(test, builder, test_prefix_list[test_prefix][builder]) 3823c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch if not actual_failures_suffixes: 383f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) # If we're not going to rebaseline the test because it's passing on this 384f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) # builder, we still want to remove the line from TestExpectations. 385f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) if test not in lines_to_remove: 386f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) lines_to_remove[test] = [] 387f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) lines_to_remove[test].append(builder) 3883c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch continue 3893c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch 3903c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch suffixes = ','.join(actual_failures_suffixes) 391e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch cmd_line = ['--suffixes', suffixes, '--builder', builder, '--test', test] 39281a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) if options.results_directory: 39381a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) cmd_line.extend(['--results-directory', options.results_directory]) 39481a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) if options.verbose: 39581a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) cmd_line.append('--verbose') 396c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) copy_baseline_commands.append(tuple([[self._tool.executable, path_to_webkit_patch, 'copy-existing-baselines-internal'] + cmd_line, cwd])) 397c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) rebaseline_commands.append(tuple([[self._tool.executable, path_to_webkit_patch, 'rebaseline-test-internal'] + cmd_line, cwd])) 398f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) return copy_baseline_commands, rebaseline_commands, lines_to_remove 3995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 400f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) def _serial_commands(self, command_results): 4015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) files_to_add = set() 402f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) files_to_delete = set() 40353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) lines_to_remove = {} 4045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for output in [result[1].split('\n') for result in command_results]: 4055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) file_added = False 4065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for line in output: 4075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) try: 4085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if line: 40953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) parsed_line = json.loads(line) 41053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) if 'add' in parsed_line: 41153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) files_to_add.update(parsed_line['add']) 412f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) if 'delete' in parsed_line: 413f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) files_to_delete.update(parsed_line['delete']) 41453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) if 'remove-lines' in parsed_line: 41553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) for line_to_remove in parsed_line['remove-lines']: 41653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) test = line_to_remove['test'] 41753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) builder = line_to_remove['builder'] 41853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) if test not in lines_to_remove: 41953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) lines_to_remove[test] = [] 42053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) lines_to_remove[test].append(builder) 4215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) file_added = True 4225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) except ValueError: 4235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) _log.debug('"%s" is not a JSON object, ignoring' % line) 4245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if not file_added: 4265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) _log.debug('Could not add file based off output "%s"' % output) 4275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 428f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) return list(files_to_add), list(files_to_delete), lines_to_remove 4295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 43081a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) def _optimize_baselines(self, test_prefix_list, verbose=False): 431f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) optimize_commands = [] 43281a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) for test in test_prefix_list: 4335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) all_suffixes = set() 43481a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) for builder in self._builders_to_fetch_from(test_prefix_list[test]): 4353c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch all_suffixes.update(self._suffixes_for_actual_failures(test, builder, test_prefix_list[test][builder])) 436f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) 4375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) # FIXME: We should propagate the platform options as well. 438f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) cmd_line = ['--no-modify-scm', '--suffixes', ','.join(all_suffixes), test] 439f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) if verbose: 440f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) cmd_line.append('--verbose') 441f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) 442f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) path_to_webkit_patch = self._tool.path() 443f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) cwd = self._tool.scm().checkout_root 444c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) optimize_commands.append(tuple([[self._tool.executable, path_to_webkit_patch, 'optimize-baselines'] + cmd_line, cwd])) 445f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) return optimize_commands 4465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 44753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) def _update_expectations_files(self, lines_to_remove): 448f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) # FIXME: This routine is way too expensive. We're creating O(n ports) TestExpectations objects. 449f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) # This is slow and uses a lot of memory. 450f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) tests = lines_to_remove.keys() 451f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) to_remove = [] 452f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) 453f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) # This is so we remove lines for builders that skip this test, e.g. Android skips most 454f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) # tests and we don't want to leave stray [ Android ] lines in TestExpectations.. 4555d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) # This is only necessary for "webkit-patch rebaseline" and for rebaselining expected 4565d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) # failures from garden-o-matic. rebaseline-expectations and auto-rebaseline will always 4575d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) # pass the exact set of ports to rebaseline. 458f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) for port_name in self._tool.port_factory.all_port_names(): 459f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) port = self._tool.port_factory.get(port_name) 460f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) generic_expectations = TestExpectations(port, tests=tests, include_overrides=False) 461f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) full_expectations = TestExpectations(port, tests=tests, include_overrides=True) 462f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) for test in tests: 463f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) if self._port_skips_test(port, test, generic_expectations, full_expectations): 464f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) for test_configuration in port.all_test_configurations(): 465f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) if test_configuration.version == port.test_configuration().version: 466f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) to_remove.append((test, test_configuration)) 467f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) 46853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) for test in lines_to_remove: 46953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) for builder in lines_to_remove[test]: 47053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) port = self._tool.port_factory.get_from_builder_name(builder) 47153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) for test_configuration in port.all_test_configurations(): 47253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) if test_configuration.version == port.test_configuration().version: 473f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) to_remove.append((test, test_configuration)) 47453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) 475f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) port = self._tool.port_factory.get() 476f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) expectations = TestExpectations(port, include_overrides=False) 477f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) expectationsString = expectations.remove_configurations(to_remove) 478f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) path = port.path_to_generic_test_expectations_file() 479f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) self._tool.filesystem.write_text_file(path, expectationsString) 480c0e19a689c8ac22cdc96b291a8d33a5d3b0b34a4Torne (Richard Coles) 481f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) def _port_skips_test(self, port, test, generic_expectations, full_expectations): 4829bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles) fs = port.host.filesystem 4839bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles) if port.default_smoke_test_only(): 4849bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles) smoke_test_filename = fs.join(port.layout_tests_dir(), 'SmokeTests') 4859bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles) if fs.exists(smoke_test_filename) and test not in fs.read_text_file(smoke_test_filename): 4869bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles) return True 4879bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles) 4889bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles) return (SKIP in full_expectations.get_expectations(test) and 4899bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles) SKIP not in generic_expectations.get_expectations(test)) 4909bbd2f5e390b01907d97ecffde80aa1b06113aacTorne (Richard Coles) 491e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch def _run_in_parallel_and_update_scm(self, commands): 4925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) command_results = self._tool.executive.run_in_parallel(commands) 4935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) log_output = '\n'.join(result[2] for result in command_results).replace('\n\n', '\n') 4945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for line in log_output.split('\n'): 4955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if line: 4965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) print >> sys.stderr, line # FIXME: Figure out how to log properly. 4975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 498f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) files_to_add, files_to_delete, lines_to_remove = self._serial_commands(command_results) 499f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) if files_to_delete: 500f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) self._tool.scm().delete_list(files_to_delete) 5015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if files_to_add: 502f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) self._tool.scm().add_list(files_to_add) 503f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) return lines_to_remove 504e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch 505e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch def _rebaseline(self, options, test_prefix_list): 506e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch for test, builders_to_check in sorted(test_prefix_list.items()): 507e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch _log.info("Rebaselining %s" % test) 508e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch for builder, suffixes in sorted(builders_to_check.items()): 509e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch _log.debug(" %s: %s" % (builder, ",".join(suffixes))) 510e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch 511f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) copy_baseline_commands, rebaseline_commands, extra_lines_to_remove = self._rebaseline_commands(test_prefix_list, options) 512f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) lines_to_remove = {} 513f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) 5148abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) if copy_baseline_commands: 5158abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) self._run_in_parallel_and_update_scm(copy_baseline_commands) 5168abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) if rebaseline_commands: 517f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) lines_to_remove = self._run_in_parallel_and_update_scm(rebaseline_commands) 518f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) 519f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) for test in extra_lines_to_remove: 520f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) if test in lines_to_remove: 521f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) lines_to_remove[test] = lines_to_remove[test] + extra_lines_to_remove[test] 522f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) else: 523f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) lines_to_remove[test] = extra_lines_to_remove[test] 524f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) 525f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) if lines_to_remove: 526f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) self._update_expectations_files(lines_to_remove) 5275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if options.optimize: 529f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles) self._run_in_parallel_and_update_scm(self._optimize_baselines(test_prefix_list, options.verbose)) 5305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5313c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch def _suffixes_for_actual_failures(self, test, builder_name, existing_suffixes): 5323c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch actual_results = self.builder_data()[builder_name].actual_results(test) 5333c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch if not actual_results: 5343c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch return set() 5353c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch return set(existing_suffixes) & TestExpectations.suffixes_for_actual_expectations_string(actual_results) 5363c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch 5375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class RebaselineJson(AbstractParallelRebaselineCommand): 5395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) name = "rebaseline-json" 5405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) help_text = "Rebaseline based off JSON passed to stdin. Intended to only be called from other scripts." 5415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def __init__(self,): 5435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) super(RebaselineJson, self).__init__(options=[ 5445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self.no_optimize_option, 5455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self.results_directory_option, 5465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ]) 5475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def execute(self, options, args, tool): 5495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self._rebaseline(options, json.loads(sys.stdin.read())) 5505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class RebaselineExpectations(AbstractParallelRebaselineCommand): 5535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) name = "rebaseline-expectations" 5545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) help_text = "Rebaselines the tests indicated in TestExpectations." 5551e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) show_in_main_help = True 5565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def __init__(self): 5585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) super(RebaselineExpectations, self).__init__(options=[ 5595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self.no_optimize_option, 5605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ] + self.platform_options) 56181a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) self._test_prefix_list = None 5625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def _tests_to_rebaseline(self, port): 5645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) tests_to_rebaseline = {} 565fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch for path, value in port.expectations_dict().items(): 566fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch expectations = TestExpectations(port, include_overrides=False, expectations_dict={path: value}) 567fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch for test in expectations.get_rebaselining_failures(): 568fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch suffixes = TestExpectations.suffixes_for_expectations(expectations.get_expectations(test)) 569fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch tests_to_rebaseline[test] = suffixes or BASELINE_SUFFIX_LIST 5705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return tests_to_rebaseline 5715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def _add_tests_to_rebaseline_for_port(self, port_name): 5735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) builder_name = builders.builder_name_for_port_name(port_name) 5745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if not builder_name: 5755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 5765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) tests = self._tests_to_rebaseline(self._tool.port_factory.get(port_name)).items() 5775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if tests: 5795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) _log.info("Retrieving results for %s from %s." % (port_name, builder_name)) 5805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for test_name, suffixes in tests: 5825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) _log.info(" %s (%s)" % (test_name, ','.join(suffixes))) 58381a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) if test_name not in self._test_prefix_list: 58481a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) self._test_prefix_list[test_name] = {} 58581a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) self._test_prefix_list[test_name][builder_name] = suffixes 5865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def execute(self, options, args, tool): 5885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) options.results_directory = None 58981a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) self._test_prefix_list = {} 5905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) port_names = tool.port_factory.all_port_names(options.platform) 5915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for port_name in port_names: 5925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self._add_tests_to_rebaseline_for_port(port_name) 59381a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) if not self._test_prefix_list: 5945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) _log.warning("Did not find any tests marked Rebaseline.") 5955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 5965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 59781a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) self._rebaseline(options, self._test_prefix_list) 5985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class Rebaseline(AbstractParallelRebaselineCommand): 6015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) name = "rebaseline" 6025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) help_text = "Rebaseline tests with results from the build bots. Shows the list of failing tests on the builders if no test names are provided." 6031e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) show_in_main_help = True 6045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) argument_names = "[TEST_NAMES]" 6055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def __init__(self): 6075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) super(Rebaseline, self).__init__(options=[ 6085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self.no_optimize_option, 6095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) # FIXME: should we support the platform options in addition to (or instead of) --builders? 6105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) self.suffixes_option, 611e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch self.results_directory_option, 6125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) optparse.make_option("--builders", default=None, action="append", help="Comma-separated-list of builders to pull new baselines from (can also be provided multiple times)"), 6135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ]) 6145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def _builders_to_pull_from(self): 616e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch chosen_names = self._tool.user.prompt_with_list("Which builder to pull results from:", self._release_builders(), can_choose_multiple=True) 6175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return [self._builder_with_name(name) for name in chosen_names] 6185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def _builder_with_name(self, name): 6205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return self._tool.buildbot_for_builder_name(name).builder_with_name(name) 6215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) def execute(self, options, args, tool): 623e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch if not args: 624e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch _log.error("Must list tests to rebaseline.") 625e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch return 626e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch 6275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if options.builders: 6285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) builders_to_check = [] 6295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for builder_names in options.builders: 6305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) builders_to_check += [self._builder_with_name(name) for name in builder_names.split(",")] 6315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else: 6325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) builders_to_check = self._builders_to_pull_from() 6335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 63481a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) test_prefix_list = {} 6355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) suffixes_to_update = options.suffixes.split(",") 6365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for builder in builders_to_check: 638e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch for test in args: 63981a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) if test not in test_prefix_list: 64081a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) test_prefix_list[test] = {} 64181a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) test_prefix_list[test][builder.name()] = suffixes_to_update 6425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if options.verbose: 64481a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) _log.debug("rebaseline-json: " + str(test_prefix_list)) 6455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 64681a5157921f1d2a7ff6aae115bfe3c139b38a5c8Torne (Richard Coles) self._rebaseline(options, test_prefix_list) 64783750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 64883750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 64983750176c3ee2cea66c8a9751271026a5901be3aBen Murdochclass AutoRebaseline(AbstractParallelRebaselineCommand): 65083750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch name = "auto-rebaseline" 65183750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch help_text = "Rebaselines any NeedsRebaseline lines in TestExpectations that have cycled through all the bots." 65283750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch AUTO_REBASELINE_BRANCH_NAME = "auto-rebaseline-temporary-branch" 65383750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 65483750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch # Rietveld uploader stinks. Limit the number of rebaselines in a given patch to keep upload from failing. 65583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch # FIXME: http://crbug.com/263676 Obviously we should fix the uploader here. 656d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) MAX_LINES_TO_REBASELINE = 200 657d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) 658d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) SECONDS_BEFORE_GIVING_UP = 300 65983750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 66083750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch def __init__(self): 66183750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch super(AutoRebaseline, self).__init__(options=[ 66283750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch # FIXME: Remove this option. 66383750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch self.no_optimize_option, 66483750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch # FIXME: Remove this option. 66583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch self.results_directory_option, 66683750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch ]) 66783750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 6685d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) def bot_revision_data(self): 66983750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch revisions = [] 670fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch for result in self.builder_data().values(): 67183750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch if result.run_was_interrupted(): 672e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) _log.error("Can't rebaseline because the latest run on %s exited early." % result.builder_name()) 673e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) return [] 674e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) revisions.append({ 675e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) "builder": result.builder_name(), 676e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) "revision": result.blink_revision(), 677e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) }) 678e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) return revisions 679e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) 6805d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) def tests_to_rebaseline(self, tool, min_revision, print_revisions): 68183750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch port = tool.port_factory.get() 68283750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch expectations_file_path = port.path_to_generic_test_expectations_file() 68383750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 68483750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch tests = set() 68583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch revision = None 68683750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch author = None 68783750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch bugs = set() 688e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) has_any_needs_rebaseline_lines = False 68983750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 69083750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch for line in tool.scm().blame(expectations_file_path).split("\n"): 691f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles) comment_index = line.find("#") 692f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles) if comment_index == -1: 693f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles) comment_index = len(line) 694f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles) line_without_comments = re.sub(r"\s+", " ", line[:comment_index].strip()) 695f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles) 696f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles) if "NeedsRebaseline" not in line_without_comments: 69783750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch continue 698e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) 699e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) has_any_needs_rebaseline_lines = True 700e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) 701f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles) parsed_line = re.match("^(\S*)[^(]*\((\S*).*?([^ ]*)\ \[[^[]*$", line_without_comments) 70283750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 70383750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch commit_hash = parsed_line.group(1) 70483750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch svn_revision = tool.scm().svn_revision_from_git_commit(commit_hash) 70583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 70683750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch test = parsed_line.group(3) 70783750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch if print_revisions: 70883750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch _log.info("%s is waiting for r%s" % (test, svn_revision)) 70983750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 71083750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch if not svn_revision or svn_revision > min_revision: 71183750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch continue 71283750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 71383750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch if revision and svn_revision != revision: 71483750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch continue 71583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 71683750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch if not revision: 71783750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch revision = svn_revision 71883750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch author = parsed_line.group(2) 71983750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 720f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles) bugs.update(re.findall("crbug\.com\/(\d+)", line_without_comments)) 72183750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch tests.add(test) 72283750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 72383750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch if len(tests) >= self.MAX_LINES_TO_REBASELINE: 72483750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch _log.info("Too many tests to rebaseline in one patch. Doing the first %d." % self.MAX_LINES_TO_REBASELINE) 72583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch break 72683750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 727e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) return tests, revision, author, bugs, has_any_needs_rebaseline_lines 72883750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 72983750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch def link_to_patch(self, revision): 73083750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch return "http://src.chromium.org/viewvc/blink?view=revision&revision=" + str(revision) 73183750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 73283750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch def commit_message(self, author, revision, bugs): 73383750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch bug_string = "" 73483750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch if bugs: 73583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch bug_string = "BUG=%s\n" % ",".join(bugs) 73683750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 73783750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch return """Auto-rebaseline for r%s 73883750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 73983750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch%s 74083750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 74183750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch%sTBR=%s 74283750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch""" % (revision, self.link_to_patch(revision), bug_string, author) 74383750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 74483750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch def get_test_prefix_list(self, tests): 74583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch test_prefix_list = {} 746fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch lines_to_remove = {} 74783750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 74883750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch for builder_name in self._release_builders(): 74983750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch port_name = builders.port_name_for_builder_name(builder_name) 75083750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch port = self._tool.port_factory.get(port_name) 75183750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch expectations = TestExpectations(port, include_overrides=True) 75283750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch for test in expectations.get_needs_rebaseline_failures(): 75383750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch if test not in tests: 75483750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch continue 755fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch 75683750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch if test not in test_prefix_list: 7573c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch lines_to_remove[test] = [] 75883750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch test_prefix_list[test] = {} 7593c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch lines_to_remove[test].append(builder_name) 7603c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch test_prefix_list[test][builder_name] = BASELINE_SUFFIX_LIST 76183750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 762fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch return test_prefix_list, lines_to_remove 76383750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 76483750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch def _run_git_cl_command(self, options, command): 76583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch subprocess_command = ['git', 'cl'] + command 76683750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch if options.verbose: 76783750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch subprocess_command.append('--verbose') 768d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) 7695d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) process = self._tool.executive.popen(subprocess_command, stdout=self._tool.executive.PIPE, stderr=self._tool.executive.STDOUT) 770d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) last_output_time = time.time() 771d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) 772d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) # git cl sometimes completely hangs. Bail if we haven't gotten any output to stdout/stderr in a while. 773d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) while process.poll() == None and time.time() < last_output_time + self.SECONDS_BEFORE_GIVING_UP: 7745d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) # FIXME: This doesn't make any sense. readline blocks, so all this code to 7755d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) # try and bail is useless. Instead, we should do the readline calls on a 7765d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) # subthread. Then the rest of this code would make sense. 777d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) out = process.stdout.readline().rstrip('\n') 778d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) if out: 779d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) last_output_time = time.time() 780d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) _log.info(out) 781d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) 782d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) if process.poll() == None: 783d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) _log.error('Command hung: %s' % subprocess_command) 784d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) return False 785d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) return True 78683750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 78783750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch # FIXME: Move this somewhere more general. 78883750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch def tree_status(self): 78983750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch blink_tree_status_url = "http://blink-status.appspot.com/status" 79083750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch status = urllib2.urlopen(blink_tree_status_url).read().lower() 791e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) if status.find('closed') != -1 or status == "0": 79283750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch return 'closed' 793e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) elif status.find('open') != -1 or status == "1": 79483750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch return 'open' 79583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch return 'unknown' 79683750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 79783750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch def execute(self, options, args, tool): 79883750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch if tool.scm().executable_name == "svn": 79983750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch _log.error("Auto rebaseline only works with a git checkout.") 80083750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch return 80183750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 80283750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch if tool.scm().has_working_directory_changes(): 80383750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch _log.error("Cannot proceed with working directory changes. Clean working directory first.") 80483750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch return 80583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 8065d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) revision_data = self.bot_revision_data() 807e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) if not revision_data: 80883750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch return 80983750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 810e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) min_revision = int(min([item["revision"] for item in revision_data])) 8115d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) tests, revision, author, bugs, has_any_needs_rebaseline_lines = self.tests_to_rebaseline(tool, min_revision, print_revisions=options.verbose) 812e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) 813e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) if options.verbose: 814e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) _log.info("Min revision across all bots is %s." % min_revision) 815e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) for item in revision_data: 816e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) _log.info("%s: r%s" % (item["builder"], item["revision"])) 81783750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 81883750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch if not tests: 81983750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch _log.debug('No tests to rebaseline.') 82083750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch return 82183750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 82283750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch if self.tree_status() == 'closed': 82383750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch _log.info('Cannot proceed. Tree is closed.') 82483750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch return 82583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 826e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) _log.info('Rebaselining %s for r%s by %s.' % (list(tests), revision, author)) 827e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) 828e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) test_prefix_list, lines_to_remove = self.get_test_prefix_list(tests) 829e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) 830e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) did_finish = False 83183750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch try: 83283750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch old_branch_name = tool.scm().current_branch() 83383750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch tool.scm().delete_branch(self.AUTO_REBASELINE_BRANCH_NAME) 83483750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch tool.scm().create_clean_branch(self.AUTO_REBASELINE_BRANCH_NAME) 83583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 836fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch # If the tests are passing everywhere, then this list will be empty. We don't need 837fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch # to rebaseline, but we'll still need to update TestExpectations. 838fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch if test_prefix_list: 839fff8884795cb540f87cf6e6d67b629519b00eb8bBen Murdoch self._rebaseline(options, test_prefix_list) 84083750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 84183750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch tool.scm().commit_locally_with_message(self.commit_message(author, revision, bugs)) 84283750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 84383750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch # FIXME: It would be nice if we could dcommit the patch without uploading, but still 84483750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch # go through all the precommit hooks. For rebaselines with lots of files, uploading 84583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch # takes a long time and sometimes fails, but we don't want to commit if, e.g. the 84683750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch # tree is closed. 847d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) did_finish = self._run_git_cl_command(options, ['upload', '-f']) 8483464d02a173573db42f8ee6bb07bb74fabf4f5f2Ben Murdoch 849d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) if did_finish: 850d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) # Uploading can take a very long time. Do another pull to make sure TestExpectations is up to date, 851d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) # so the dcommit can go through. 852d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) # FIXME: Log the pull and dcommit stdout/stderr to the log-server. 853d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) tool.executive.run_command(['git', 'pull']) 8543464d02a173573db42f8ee6bb07bb74fabf4f5f2Ben Murdoch 855d6cdb82654e8f3343a693ca752d5c4cee0324e17Torne (Richard Coles) self._run_git_cl_command(options, ['dcommit', '-f']) 856e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) except Exception as e: 857e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) _log.error(e) 85883750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch finally: 859e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) if did_finish: 860e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self._run_git_cl_command(options, ['set_close']) 86183750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch tool.scm().ensure_cleanly_tracking_remote_master() 86283750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch tool.scm().checkout_branch(old_branch_name) 86383750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch tool.scm().delete_branch(self.AUTO_REBASELINE_BRANCH_NAME) 86483750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 86583750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 86683750176c3ee2cea66c8a9751271026a5901be3aBen Murdochclass RebaselineOMatic(AbstractDeclarativeCommand): 86783750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch name = "rebaseline-o-matic" 86883750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch help_text = "Calls webkit-patch auto-rebaseline in a loop." 8691e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) show_in_main_help = True 87083750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 87183750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch SLEEP_TIME_IN_SECONDS = 30 8725d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) LOG_SERVER = 'blinkrebaseline.appspot.com' 873c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) QUIT_LOG = '##QUIT##' 8745d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) 8755d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) # Uploaded log entries append to the existing entry unless the 8765d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) # newentry flag is set. In that case it starts a new entry to 8775d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) # start appending to. 8785d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) def _log_to_server(self, log='', is_new_entry=False): 8795d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) query = { 8805d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) 'log': log, 8815d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) } 8825d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) if is_new_entry: 8835d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) query['newentry'] = 'on' 884c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) try: 885c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) urllib2.urlopen("http://" + self.LOG_SERVER + "/updatelog", data=urllib.urlencode(query)) 886c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) except: 887c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) traceback.print_exc(file=sys.stderr) 888c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) 889c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) def _log_to_server_thread(self): 890c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) is_new_entry = True 891c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) while True: 892c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) messages = [self._log_queue.get()] 893c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) while not self._log_queue.empty(): 894c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) messages.append(self._log_queue.get()) 895c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) self._log_to_server('\n'.join(messages), is_new_entry=is_new_entry) 896c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) is_new_entry = False 897c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) if self.QUIT_LOG in messages: 898c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) return 899c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) 900c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) def _post_log_to_server(self, log): 901c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) self._log_queue.put(log) 9025d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) 9035d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) def _log_line(self, handle): 9045d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) out = handle.readline().rstrip('\n') 9055d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) if out: 9065d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) if self._verbose: 9075d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) print out 908c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) self._post_log_to_server(out) 9095d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) return out 9105d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) 9115d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) def _run_logged_command(self, command): 9125d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) process = self._tool.executive.popen(command, stdout=self._tool.executive.PIPE, stderr=self._tool.executive.STDOUT) 9135d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) 9145d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) out = self._log_line(process.stdout) 9155d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) while out: 9165d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) # FIXME: This should probably batch up lines if they're available and log to the server once. 9175d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) out = self._log_line(process.stdout) 9185d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) 9195d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) def _do_one_rebaseline(self): 920c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) self._log_queue = Queue.Queue(256) 921c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) log_thread = threading.Thread(name='LogToServer', target=self._log_to_server_thread) 922c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) log_thread.start() 9235d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) try: 9245d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) old_branch_name = self._tool.scm().current_branch() 9255d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) self._run_logged_command(['git', 'pull']) 9265d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) rebaseline_command = [self._tool.filesystem.join(self._tool.scm().checkout_root, 'Tools', 'Scripts', 'webkit-patch'), 'auto-rebaseline'] 9275d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) if self._verbose: 9285d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) rebaseline_command.append('--verbose') 9295d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) self._run_logged_command(rebaseline_command) 9305d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) except: 931e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self._log_queue.put(self.QUIT_LOG) 9325d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) traceback.print_exc(file=sys.stderr) 9335d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) # Sometimes git crashes and leaves us on a detached head. 9345d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) self._tool.scm().checkout_branch(old_branch_name) 935e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) else: 936e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles) self._log_queue.put(self.QUIT_LOG) 937c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles) log_thread.join() 93883750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch 93983750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch def execute(self, options, args, tool): 9405d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) self._verbose = options.verbose 94183750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch while True: 9425d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles) self._do_one_rebaseline() 94383750176c3ee2cea66c8a9751271026a5901be3aBen Murdoch time.sleep(self.SLEEP_TIME_IN_SECONDS) 944