1#!/usr/bin/env python 2# Copyright 2015 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"""Updates the 64 bit d8 binary for the current OS to match the v8 version used 7in the current version of the specified Chromium channel. If no channel is 8specified, we default to the 'stable' channel. 9 10This script assumes that git is installed and the computer meets all 11other prerequisites to build v8 normally (like having depot_tools installed and 12in $PATH). 13 14Example usage: 15$ tracing/bin/update_v8 16""" 17 18import json 19import os 20import platform 21import re 22import shutil 23import subprocess 24import sys 25import tempfile 26import urllib2 27 28OMAHAPROXY_VERSION_MAP_URL = 'https://omahaproxy.appspot.com/all.json' 29 30V8_PATH = os.path.join( 31 os.path.dirname(os.path.abspath(__file__)), os.path.pardir, 'third_party', 32 'v8') 33V8_BINARY_PATH = os.path.join(V8_PATH, '{os}', '{arch}', 'd8') 34V8_README_PATH = os.path.join(V8_PATH, 'README.chromium') 35 36V8_CHECKOUT_BINARY_PATH = os.path.join( 37 '{v8_root}', 'v8', 'out', 'Release', 'd8') 38V8_GENERATE_GYP_CMD = os.path.join('build', 'gyp_v8') + ' -Dtarget_arch={arch}' 39V8_COMPILE_CMD = 'ninja -C {0} d8'.format(os.path.join('out', 'Release')) 40V8_STRIP_CMD = 'strip -x {0}'.format(os.path.join('out', 'Release', 'd8')) 41 42VALID_CHANNEL_LIST = ['stable', 'canary', 'beta', 'dev'] 43# Dict from the acceptable return values for Python's platform.system() to the 44# corresponding Chromium OS name. 45PYTHON_SYSTEM_TO_CHROME_OS = { 46 'Linux': 'linux', 47 'Windows': 'win', 48 'Darwin': 'mac' 49} 50# Dict from the acceptable return values for Python's platform.machine() to the 51# corresponding ninja architecture name. 52PYTHON_MACHINE_TO_NINJA_ARCH = { 53 'x86_64': 'x64' 54} 55 56def Main(args): 57 if len(args) > 1: 58 print('Usage: update_v8 [TARGET_CHANNEL]') 59 return 1 60 61 target_channel = args[0] if len(args) == 1 else 'stable' 62 target_arch = platform.machine() 63 64 if target_channel not in VALID_CHANNEL_LIST: 65 print('Invalid target channel. Valid: {0}'.format(VALID_CHANNEL_LIST)) 66 return 1 67 68 if platform.system() not in PYTHON_SYSTEM_TO_CHROME_OS: 69 print('System not supported. Valid: {0}'.format( 70 PYTHON_SYSTEM_TO_CHROME_OS.keys())) 71 return 1 72 target_os = PYTHON_SYSTEM_TO_CHROME_OS[platform.system()] 73 74 if target_arch not in PYTHON_MACHINE_TO_NINJA_ARCH: 75 print('Invalid target architecture. Valid: {0}'.format( 76 PYTHON_MACHINE_TO_NINJA_ARCH.keys())) 77 return 1 78 79 v8_version = GetV8Version(target_os, target_channel) 80 UpdateV8Binary(v8_version, target_os, target_arch) 81 UpdateReadmeFile(v8_version, target_os) 82 83 return 0 84 85def GetV8Version(target_os, target_channel): 86 """Returns the v8 version that corresponds to the specified OS and channel.""" 87 # Fetch the current version map from omahaproxy. 88 response = urllib2.urlopen(OMAHAPROXY_VERSION_MAP_URL) 89 versions = json.loads(response.read()) 90 91 # Return the v8 version that corresponds to the target OS and channel in the 92 # version map. 93 v8_version = None 94 for curr_os in versions: 95 for curr_version in curr_os['versions']: 96 if (curr_version['os'] == target_os and 97 curr_version['channel'] == target_channel): 98 return curr_version['v8_version'] 99 100def UpdateV8Binary(v8_version, target_os, target_arch): 101 """Updates the catapult V8 binary for the specified OS to be the specified V8 102 version.""" 103 # Clone v8, checkout the version that corresponds to our target OS and target 104 # channel, and build the d8 binary. 105 with TempDir() as v8_checkout_path: 106 with ChangeDirectory(v8_checkout_path): 107 subprocess.check_call('fetch v8', shell=True) 108 with ChangeDirectory('v8'): 109 subprocess.check_call('git checkout {0}'.format(v8_version), shell=True) 110 111 os.environ['GYP_DEFINES'] += ' v8_use_external_startup_data=0' 112 os.environ['GYP_GENERATORS'] = 'ninja' 113 ninja_arch = PYTHON_MACHINE_TO_NINJA_ARCH[target_arch] 114 subprocess.check_call( 115 V8_GENERATE_GYP_CMD.format(arch=ninja_arch), shell=True) 116 subprocess.check_call(V8_COMPILE_CMD, shell=True) 117 if target_os in ['linux', 'mac']: 118 subprocess.check_call(V8_STRIP_CMD, shell=True) 119 120 # Move the d8 binary into place. 121 d8_src = V8_CHECKOUT_BINARY_PATH.format(v8_root=v8_checkout_path) 122 d8_dst = V8_BINARY_PATH.format(os=target_os, arch=target_arch) 123 124 shutil.move(d8_src, d8_dst) 125 126def UpdateReadmeFile(v8_version, target_os): 127 """Updates the V8 version number in the V8 README.chromium file.""" 128 # Get the contents of the new README file with the replaced version number. 129 new_readme_contents = '' 130 with open(V8_README_PATH, 'r') as v8_readme: 131 new_readme_contents = re.sub(r'[0-9\.]+ \({0}\)'.format(target_os), 132 r'{0} ({1})'.format(v8_version, target_os), 133 v8_readme.read()) 134 135 # Overwrite the old README file with the new one. 136 with open(V8_README_PATH, 'w') as v8_readme: 137 v8_readme.write(new_readme_contents) 138 139class ChangeDirectory: 140 """A context manager that changes a directory while in scope.""" 141 def __init__(self, newPath): 142 self.newPath = newPath 143 144 def __enter__(self): 145 self.oldPath = os.getcwd() 146 os.chdir(self.newPath) 147 148 def __exit__(self, etype, value, traceback): 149 os.chdir(self.oldPath) 150 151class TempDir: 152 """A context manager that creates a temporary directory while in scope.""" 153 def __enter__(self): 154 self.path = tempfile.mkdtemp() 155 print "creating {0}".format(self.path) 156 return self.path 157 158 def __exit__(self, etype, value, traceback): 159 shutil.rmtree(self.path) 160 161if __name__ == '__main__': 162 sys.exit(Main(sys.argv[1:])) 163