OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. |
| 5 |
| 6 """Automate the setup process of Chrome Endure environment. |
| 7 |
| 8 Usage: |
| 9 python endure_setup.py [option] |
| 10 |
| 11 We use <ENDURE_DIR> to refer to the root directory in which Chrome Endure |
| 12 is set up. By default, <ENDURE_DIR> is the current working directory. |
| 13 |
| 14 First, run: |
| 15 >python endure_setup.py |
| 16 This command will automatically setup Chrome Endure in <ENDURE_DIR>. |
| 17 |
| 18 Next, run your first endure test by: |
| 19 >TEST_LENGTH=30 LOCAL_PERF_DIR="<ENDURE_DIR>/chrome_graph" \\ |
| 20 python <ENDURE_DIR>/src/chrome/test/functional/perf_endure.py \\ |
| 21 perf_endure.ChromeEndureGmailTest.testGmailComposeDiscard \\ |
| 22 The above commands runs a Chrome Endure test for 30 seconds and saves |
| 23 the results to <ENDURE_DIR>/chrome_graph. |
| 24 |
| 25 Last, to view the graphs, run another script endure_server.py |
| 26 within <ENDURE_DIR> to start a local HTTP server that serves |
| 27 the graph directory, see endure_server.py for details. |
| 28 |
| 29 Use python endure_setup.py --help for more options. |
| 30 |
| 31 This script depends on the following modules |
| 32 (which will be downloaded automatically): |
| 33 depot_tools |
| 34 src/chrome/test/pyautolib/fetch_prebuilt_pyauto.py |
| 35 |
| 36 Supported platforms: Linux and Linux_x64. |
| 37 """ |
| 38 |
| 39 import logging |
| 40 import optparse |
| 41 import os |
| 42 import platform |
| 43 import shutil |
| 44 import subprocess |
| 45 import sys |
| 46 import urllib |
| 47 import urllib2 |
| 48 import zipfile |
| 49 |
| 50 URLS = {'depot_tools': ('http://src.chromium.org' |
| 51 '/chrome/trunk/tools/depot_tools'), |
| 52 'pyauto': ('https://src.chromium.org/' |
| 53 'chrome/trunk/src/chrome/test/functional.DEPS'), |
| 54 'binary': ('http://commondatastorage.googleapis.com/' |
| 55 'chromium-browser-continuous/{os_type}/{revision}'), |
| 56 } |
| 57 |
| 58 |
| 59 class SetupError(Exception): |
| 60 """Catch errors in setting up Chrome Endure.""" |
| 61 pass |
| 62 |
| 63 |
| 64 class HelpFormatter(optparse.IndentedHelpFormatter): |
| 65 """Format the help message of this script.""" |
| 66 |
| 67 def format_description(self, description): |
| 68 """Override to keep the original format of the description.""" |
| 69 return description + '\n' if description else '' |
| 70 |
| 71 |
| 72 def Main(argv): |
| 73 """Fetch Chrome Endure. |
| 74 |
| 75 Usage: |
| 76 python endure_setup.py [options] |
| 77 |
| 78 Examples: |
| 79 >python endure_setup.py |
| 80 Fetch the latest version of Chrome Endure to the current |
| 81 working directory. |
| 82 |
| 83 >python endure_setup.py --endure-dir=/home/user/endure_dir |
| 84 Fetch the latest version of Chrome Endure to /home/user/endure_dir. |
| 85 """ |
| 86 parser = optparse.OptionParser( |
| 87 formatter=HelpFormatter(), description=Main.__doc__) |
| 88 parser.add_option( |
| 89 '-d', '--endure-dir', type='string', default=os.getcwd(), |
| 90 help='Directory in which to setup or update. ' \ |
| 91 'Default value is the current working directory.') |
| 92 # TODO(fdeng): remove this option once the Chrome Endure |
| 93 # graphing code is checked into chrome tree. |
| 94 parser.add_option( |
| 95 '-g', '--graph-zip-url', type='string', default=None, |
| 96 help='URL to a zip file containing the chrome graphs.') |
| 97 os_type = GetCurrentOSType() |
| 98 if not os_type.startswith('Linux'): |
| 99 raise SetupError('Only support Linux or Linux_x64, %s found' |
| 100 % os_type) |
| 101 options, _ = parser.parse_args(argv) |
| 102 endure_dir = os.path.abspath(options.endure_dir) |
| 103 depot_dir = os.path.join(endure_dir, 'depot_tools') |
| 104 gclient = os.path.join(depot_dir, 'gclient') |
| 105 fetch_py = os.path.join(endure_dir, 'src', 'chrome', |
| 106 'test', 'pyautolib', |
| 107 'fetch_prebuilt_pyauto.py') |
| 108 binary_dir = os.path.join(endure_dir, 'src', 'out', 'Release') |
| 109 graph_zip_url = options.graph_zip_url |
| 110 graph_dir = os.path.join(endure_dir, 'chrome_graph') |
| 111 |
| 112 if not os.path.isdir(endure_dir): |
| 113 os.makedirs(endure_dir) |
| 114 |
| 115 logging.info('Fetching depot tools...') |
| 116 FetchDepot(depot_dir) |
| 117 logging.info('Fetching PyAuto (python code)...') |
| 118 FetchPyAuto(gclient, endure_dir) |
| 119 logging.info('Fetching binaries(chrome, pyautolib, chrome driver)...') |
| 120 FetchBinaries(fetch_py, binary_dir, os_type) |
| 121 # TODO(fdeng): remove this after it is checked into the chrome tree. |
| 122 logging.info('Fetching chrome graphing files...') |
| 123 FetchGraph(graph_zip_url, graph_dir) |
| 124 return 0 |
| 125 |
| 126 |
| 127 def FetchDepot(depot_dir): |
| 128 """Fetch depot_tools. |
| 129 |
| 130 Args: |
| 131 depot_dir: The directory where depot_tools will be checked out. |
| 132 |
| 133 Raises: |
| 134 SetupError: If fail. |
| 135 """ |
| 136 if subprocess.call(['svn', 'co', URLS['depot_tools'], depot_dir]) != 0: |
| 137 raise SetupError('Error found when checking out depot_tools.') |
| 138 if not CheckDepot(depot_dir): |
| 139 raise SetupError('Could not get depot_tools.') |
| 140 |
| 141 |
| 142 def CheckDepot(depot_dir): |
| 143 """Check that some expected depot_tools files exist. |
| 144 |
| 145 Args: |
| 146 depot_dir: The directory where depot_tools are checked out. |
| 147 |
| 148 Returns: |
| 149 True if check passes otherwise False. |
| 150 """ |
| 151 gclient = os.path.join(depot_dir, 'gclient') |
| 152 gclient_py = os.path.join(depot_dir, 'gclient.py') |
| 153 files = [gclient, gclient_py] |
| 154 for f in files: |
| 155 if not os.path.exists(f): |
| 156 return False |
| 157 try: |
| 158 subprocess.call([gclient, '--version']) |
| 159 except OSError: |
| 160 return False |
| 161 return True |
| 162 |
| 163 |
| 164 def FetchPyAuto(gclient, endure_dir): |
| 165 """Use gclient to fetch python code. |
| 166 |
| 167 Args: |
| 168 gclient: The path to the gclient executable. |
| 169 endure_dir: Directory where Chrome Endure and |
| 170 its dependencies will be checked out. |
| 171 |
| 172 Raises: |
| 173 SetupError: if fails. |
| 174 """ |
| 175 cur_dir = os.getcwd() |
| 176 os.chdir(endure_dir) |
| 177 config_cmd = [gclient, 'config', URLS['pyauto']] |
| 178 if subprocess.call(config_cmd) != 0: |
| 179 raise SetupError('Running "%s" failed.' % ' '.join(config_cmd)) |
| 180 sync_cmd = [gclient, 'sync'] |
| 181 if subprocess.call(sync_cmd) != 0: |
| 182 raise SetupError('Running "%s" failed.' % ' '.join(sync_cmd)) |
| 183 CheckPyAuto(endure_dir) |
| 184 logging.info('Sync PyAuto python code done.') |
| 185 os.chdir(cur_dir) |
| 186 |
| 187 |
| 188 def CheckPyAuto(endure_dir): |
| 189 """Sanity check for Chrome Endure code. |
| 190 |
| 191 Args: |
| 192 endure_dir: Directory of Chrome Endure and its dependencies. |
| 193 |
| 194 Raises: |
| 195 SetupError: If fails. |
| 196 """ |
| 197 fetch_py = os.path.join(endure_dir, 'src', 'chrome', |
| 198 'test', 'pyautolib', |
| 199 'fetch_prebuilt_pyauto.py') |
| 200 pyauto_py = os.path.join(endure_dir, 'src', |
| 201 'chrome', 'test', |
| 202 'pyautolib', 'pyauto.py') |
| 203 files = [fetch_py, pyauto_py] |
| 204 for f in files: |
| 205 if not os.path.exists(f): |
| 206 raise SetupError('Checking %s failed.' % f) |
| 207 |
| 208 |
| 209 def FetchBinaries(fetch_py, binary_dir, os_type): |
| 210 """Get the prebuilt binaries from continuous build archive. |
| 211 |
| 212 Args: |
| 213 fetch_py: Path to the script which fetches pre-built binaries. |
| 214 binary_dir: Directory of the pre-built binaries. |
| 215 os_type: 'Mac', 'Win', 'Linux', 'Linux_x64'. |
| 216 |
| 217 Raises: |
| 218 SetupError: If fails. |
| 219 """ |
| 220 revision = GetLatestRevision(os_type) |
| 221 logging.info('Cleaning %s', binary_dir) |
| 222 if os.path.exists(binary_dir): |
| 223 shutil.rmtree(binary_dir) |
| 224 logging.info('Downloading binaries...') |
| 225 cmd = [fetch_py, '-d', binary_dir, |
| 226 URLS['binary'].format( |
| 227 os_type=os_type, revision=revision)] |
| 228 if subprocess.call(cmd) == 0 and os.path.exists(binary_dir): |
| 229 logging.info('Binaries at revision %s', revision) |
| 230 else: |
| 231 raise SetupError('Running "%s" failed.' % ' '.join(cmd)) |
| 232 |
| 233 |
| 234 def FetchGraph(graph_zip_url, graph_dir): |
| 235 """Fetch graph code. |
| 236 |
| 237 Args: |
| 238 graph_zip_url: The url to a zip file containing the chrome graphs. |
| 239 graph_dir: Directory of the chrome graphs. |
| 240 |
| 241 Raises: |
| 242 SetupError: if unable to retrive the zip file. |
| 243 """ |
| 244 # TODO(fdeng): remove this function once chrome graph |
| 245 # is checked into chrome tree. |
| 246 if not graph_zip_url: |
| 247 logging.info( |
| 248 'Skip fetching chrome graphs' + |
| 249 ' since --graph-zip-url is not set.') |
| 250 return |
| 251 graph_zip = urllib.urlretrieve(graph_zip_url)[0] |
| 252 if graph_zip is None or not os.path.exists(graph_zip): |
| 253 raise SetupError('Unable to retrieve %s' % graph_zip_url) |
| 254 if not os.path.exists(graph_dir): |
| 255 os.mkdir(graph_dir) |
| 256 UnzipFilenameToDir(graph_zip, graph_dir) |
| 257 logging.info('Graph code is downloaded to %s', graph_dir) |
| 258 |
| 259 |
| 260 def GetCurrentOSType(): |
| 261 """Get a string representation for the current OS. |
| 262 |
| 263 Returns: |
| 264 'Mac', 'Win', 'Linux', or 'Linux_64'. |
| 265 |
| 266 Raises: |
| 267 RuntimeError: if OS can't be identified. |
| 268 """ |
| 269 if sys.platform == 'darwin': |
| 270 os_type = 'Mac' |
| 271 if sys.platform == 'win32': |
| 272 os_type = 'Win' |
| 273 if sys.platform.startswith('linux'): |
| 274 os_type = 'Linux' |
| 275 if platform.architecture()[0] == '64bit': |
| 276 os_type += '_x64' |
| 277 else: |
| 278 raise RuntimeError('Unknown platform') |
| 279 return os_type |
| 280 |
| 281 |
| 282 def GetLatestRevision(os_type): |
| 283 """Figure out the latest revision number of the prebuilt binary archive. |
| 284 |
| 285 Args: |
| 286 os_type: 'Mac', 'Win', 'Linux', or 'Linux_64'. |
| 287 |
| 288 Returns: |
| 289 A string of latest revision number. |
| 290 |
| 291 Raises: |
| 292 SetupError: If unable to get the latest revision number. |
| 293 """ |
| 294 last_change_url = ('http://commondatastorage.googleapis.com/' |
| 295 'chromium-browser-continuous/%s/LAST_CHANGE' % os_type) |
| 296 response = urllib2.urlopen(last_change_url) |
| 297 last_change = response.read() |
| 298 if not last_change: |
| 299 raise SetupError('Unable to get the latest revision number from %s' % |
| 300 last_change_url) |
| 301 return last_change |
| 302 |
| 303 |
| 304 def UnzipFilenameToDir(filename, directory): |
| 305 """Unzip |filename| to directory |directory|. |
| 306 |
| 307 This works with as low as python2.4 (used on win). |
| 308 (Code is adapted from fetch_prebuilt_pyauto.py) |
| 309 """ |
| 310 # TODO(fdeng): remove this function as soon as the Chrome Endure |
| 311 # graphing code is checked into the chrome tree. |
| 312 zf = zipfile.ZipFile(filename) |
| 313 pushd = os.getcwd() |
| 314 if not os.path.isdir(directory): |
| 315 os.mkdir(directory) |
| 316 os.chdir(directory) |
| 317 # Extract files. |
| 318 for info in zf.infolist(): |
| 319 name = info.filename |
| 320 if name.endswith('/'): # dir |
| 321 if not os.path.isdir(name): |
| 322 os.makedirs(name) |
| 323 else: # file |
| 324 directory = os.path.dirname(name) |
| 325 if directory and not os.path.isdir(directory): |
| 326 os.makedirs(directory) |
| 327 out = open(name, 'wb') |
| 328 out.write(zf.read(name)) |
| 329 out.close() |
| 330 # Set permissions. Permission info in external_attr is shifted 16 bits. |
| 331 os.chmod(name, info.external_attr >> 16L) |
| 332 os.chdir(pushd) |
| 333 |
| 334 |
| 335 if '__main__' == __name__: |
| 336 logging.basicConfig(format='[%(levelname)s] %(message)s', level=logging.DEBUG) |
| 337 sys.exit(Main(sys.argv[1:])) |
OLD | NEW |