1#!/usr/bin/env python 2# 3# Copyright (C) 2015 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17 18"""Update the prebuilt clang from the build server.""" 19from __future__ import print_function 20 21import argparse 22import inspect 23import os 24import shutil 25import subprocess 26import sys 27 28 29THIS_DIR = os.path.realpath(os.path.dirname(__name__)) 30ANDROID_DIR = os.path.realpath(os.path.join(THIS_DIR, '../..')) 31 32BRANCH = 'aosp-llvm' 33 34 35def android_path(*args): 36 return os.path.join(ANDROID_DIR, *args) 37 38 39class ArgParser(argparse.ArgumentParser): 40 def __init__(self): 41 super(ArgParser, self).__init__( 42 description=inspect.getdoc(sys.modules[__name__])) 43 44 self.add_argument( 45 'build', metavar='BUILD', 46 help='Build number to pull from the build server.') 47 48 self.add_argument( 49 '-b', '--bug', type=int, 50 help='Bug to reference in commit message.') 51 52 self.add_argument( 53 '--use-current-branch', action='store_true', 54 help='Do not repo start a new branch for the update.') 55 56 57def host_to_build_host(host): 58 """Gets the build host name for an NDK host tag. 59 60 The Windows builds are done from Linux. 61 """ 62 return { 63 'darwin': 'mac', 64 'linux': 'linux', 65 'windows': 'linux', 66 }[host] 67 68 69def build_name(host): 70 """Gets the build name for a given host. 71 72 The build name is either "linux" or "darwin", with any Windows builds 73 coming from "linux". 74 """ 75 return { 76 'darwin': 'darwin', 77 'linux': 'linux', 78 'windows': 'linux', 79 }[host] 80 81 82def package_name(build_number, host): 83 """Returns the file name for a given package configuration. 84 85 >>> package_name('1234', 'linux') 86 'clang-1234-linux-x86.tar.bz2' 87 """ 88 return 'clang-{}-{}-x86.tar.bz2'.format(build_number, host) 89 90 91def download_build(host, build_number, download_dir): 92 url_base = 'https://android-build-uber.corp.google.com' 93 path = 'builds/{branch}-{build_host}-{build_name}/{build_num}'.format( 94 branch=BRANCH, 95 build_host=host_to_build_host(host), 96 build_name=build_name(host), 97 build_num=build_number) 98 99 pkg_name = package_name(build_number, host) 100 url = '{}/{}/{}'.format(url_base, path, pkg_name) 101 102 TIMEOUT = '60' # In seconds. 103 out_file_path = os.path.join(download_dir, pkg_name) 104 with open(out_file_path, 'w') as out_file: 105 print('Downloading {} to {}'.format(url, out_file_path)) 106 subprocess.check_call( 107 ['sso_client', '--location', '--request_timeout', TIMEOUT, url], 108 stdout=out_file) 109 return out_file_path 110 111 112def extract_package(package, install_dir): 113 cmd = ['tar', 'xf', package, '-C', install_dir] 114 print('Extracting {}...'.format(package)) 115 subprocess.check_call(cmd) 116 117 118def update_clang(host, build_number, use_current_branch, download_dir, bug): 119 host_tag = host + '-x86' 120 prebuilt_dir = android_path('prebuilts/clang/host', host_tag) 121 os.chdir(prebuilt_dir) 122 123 if not use_current_branch: 124 subprocess.check_call( 125 ['repo', 'start', 'update-clang-{}'.format(build_number), '.']) 126 127 package = download_build(host, build_number, download_dir) 128 129 install_subdir = 'clang-' + build_number 130 extract_package(package, prebuilt_dir) 131 132 print('Adding files to index...') 133 subprocess.check_call(['git', 'add', install_subdir]) 134 135 version_file_path = os.path.join(install_subdir, 'AndroidVersion.txt') 136 with open(version_file_path) as version_file: 137 version = version_file.read().strip() 138 139 print('Committing update...') 140 message_lines = [ 141 'Update prebuilt Clang to build {}.'.format(build_number), 142 '', 143 'Built from version {}.'.format(version), 144 ] 145 if bug is not None: 146 message_lines.append('') 147 message_lines.append('Bug: http://b/{}'.format(bug)) 148 message = '\n'.join(message_lines) 149 subprocess.check_call(['git', 'commit', '-m', message]) 150 151 152def main(): 153 args = ArgParser().parse_args() 154 155 download_dir = os.path.realpath('.download') 156 if os.path.isdir(download_dir): 157 shutil.rmtree(download_dir) 158 os.makedirs(download_dir) 159 160 try: 161 hosts = ('darwin', 'linux', 'windows') 162 for host in hosts: 163 update_clang(host, args.build, args.use_current_branch, 164 download_dir, args.bug) 165 finally: 166 shutil.rmtree(download_dir) 167 168 169if __name__ == '__main__': 170 main() 171