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 35 from webkitpy.common.system import logutils 36 from 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 52 def clear_cached_configuration(): 53 global _have_determined_configuration, _configuration 54 _have_determined_configuration = False 55 _configuration = "Release" 56 57 58 class 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