1#!/usr/bin/env python 2# Copyright (C) 2010 Google Inc. All rights reserved. 3# 4# Redistribution and use in source and binary forms, with or without 5# modification, are permitted provided that the following conditions are 6# met: 7# 8# * Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# * Redistributions in binary form must reproduce the above 11# copyright notice, this list of conditions and the following disclaimer 12# in the documentation and/or other materials provided with the 13# distribution. 14# * Neither the name of Google Inc. nor the names of its 15# contributors may be used to endorse or promote products derived from 16# this software without specific prior written permission. 17# 18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 30"""Wrapper objects for WebKit-specific utility routines.""" 31 32# FIXME: This file needs to be unified with common/checkout/scm.py and 33# common/config/ports.py . 34 35from webkitpy.common.system import logutils 36from webkitpy.common.system import executive 37 38 39_log = logutils.get_logger(__file__) 40 41# 42# FIXME: This is used to record if we've already hit the filesystem to look 43# for a default configuration. We cache this to speed up the unit tests, 44# but this can be reset with clear_cached_configuration(). This should be 45# replaced with us consistently using MockConfigs() for tests that don't 46# hit the filesystem at all and provide a reliable value. 47# 48_have_determined_configuration = False 49_configuration = "Release" 50 51 52def clear_cached_configuration(): 53 global _have_determined_configuration, _configuration 54 _have_determined_configuration = False 55 _configuration = "Release" 56 57 58class Config(object): 59 _FLAGS_FROM_CONFIGURATIONS = { 60 "Debug": "--debug", 61 "Release": "--release", 62 } 63 64 def __init__(self, executive, filesystem): 65 self._executive = executive 66 self._filesystem = filesystem 67 self._webkit_base_dir = None 68 self._default_configuration = None 69 self._build_directories = {} 70 71 def build_directory(self, configuration): 72 """Returns the path to the build directory for the configuration.""" 73 if configuration: 74 flags = ["--configuration", 75 self._FLAGS_FROM_CONFIGURATIONS[configuration]] 76 else: 77 configuration = "" 78 flags = ["--top-level"] 79 80 if not self._build_directories.get(configuration): 81 args = ["perl", self._script_path("webkit-build-directory")] + flags 82 self._build_directories[configuration] = ( 83 self._executive.run_command(args).rstrip()) 84 85 return self._build_directories[configuration] 86 87 def build_dumprendertree(self, configuration): 88 """Builds DRT in the given configuration. 89 90 Returns True if the build was successful and up-to-date.""" 91 flag = self._FLAGS_FROM_CONFIGURATIONS[configuration] 92 exit_code = self._executive.run_command([ 93 self._script_path("build-dumprendertree"), flag], 94 return_exit_code=True) 95 if exit_code != 0: 96 _log.error("Failed to build DumpRenderTree") 97 return False 98 return True 99 100 def default_configuration(self): 101 """Returns the default configuration for the user. 102 103 Returns the value set by 'set-webkit-configuration', or "Release" 104 if that has not been set. This mirrors the logic in webkitdirs.pm.""" 105 if not self._default_configuration: 106 self._default_configuration = self._determine_configuration() 107 if not self._default_configuration: 108 self._default_configuration = 'Release' 109 if self._default_configuration not in self._FLAGS_FROM_CONFIGURATIONS: 110 _log.warn("Configuration \"%s\" is not a recognized value.\n" % 111 self._default_configuration) 112 _log.warn("Scripts may fail. " 113 "See 'set-webkit-configuration --help'.") 114 return self._default_configuration 115 116 def path_from_webkit_base(self, *comps): 117 return self._filesystem.join(self.webkit_base_dir(), *comps) 118 119 def webkit_base_dir(self): 120 """Returns the absolute path to the top of the WebKit tree. 121 122 Raises an AssertionError if the top dir can't be determined.""" 123 # Note: this code somewhat duplicates the code in 124 # scm.find_checkout_root(). However, that code only works if the top 125 # of the SCM repository also matches the top of the WebKit tree. The 126 # Chromium ports, for example, only check out subdirectories like 127 # Tools/Scripts, and so we still have to do additional work 128 # to find the top of the tree. 129 # 130 # This code will also work if there is no SCM system at all. 131 if not self._webkit_base_dir: 132 abspath = self._filesystem.abspath(__file__) 133 self._webkit_base_dir = abspath[0:abspath.find('Tools') - 1] 134 return self._webkit_base_dir 135 136 def _script_path(self, script_name): 137 return self._filesystem.join(self.webkit_base_dir(), "Tools", 138 "Scripts", script_name) 139 140 def _determine_configuration(self): 141 # This mirrors the logic in webkitdirs.pm:determineConfiguration(). 142 # 143 # FIXME: See the comment at the top of the file regarding unit tests 144 # and our use of global mutable static variables. 145 global _have_determined_configuration, _configuration 146 if not _have_determined_configuration: 147 contents = self._read_configuration() 148 if not contents: 149 contents = "Release" 150 if contents == "Deployment": 151 contents = "Release" 152 if contents == "Development": 153 contents = "Debug" 154 _configuration = contents 155 _have_determined_configuration = True 156 return _configuration 157 158 def _read_configuration(self): 159 try: 160 configuration_path = self._filesystem.join(self.build_directory(None), 161 "Configuration") 162 if not self._filesystem.exists(configuration_path): 163 return None 164 except (OSError, executive.ScriptError): 165 return None 166 167 return self._filesystem.read_text_file(configuration_path).rstrip() 168