Home | History | Annotate | Download | only in clang
      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."""
     19 from __future__ import print_function
     20 
     21 import argparse
     22 import inspect
     23 import os
     24 import shutil
     25 import subprocess
     26 import sys
     27 
     28 
     29 THIS_DIR = os.path.realpath(os.path.dirname(__name__))
     30 ANDROID_DIR = os.path.realpath(os.path.join(THIS_DIR, '../..'))
     31 
     32 BRANCH = 'aosp-llvm'
     33 
     34 
     35 def android_path(*args):
     36     return os.path.join(ANDROID_DIR, *args)
     37 
     38 
     39 class 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 
     57 def 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 
     69 def 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 
     82 def manifest_name(build_number):
     83     """Returns the manifest file name for a given build.
     84 
     85     >>> manifest_name('1234')
     86     'manifest_1234.xml'
     87     """
     88     return 'manifest_{}.xml'.format(build_number)
     89 
     90 
     91 def package_name(build_number, host):
     92     """Returns the file name for a given package configuration.
     93 
     94     >>> package_name('1234', 'linux')
     95     'clang-1234-linux-x86.tar.bz2'
     96     """
     97     return 'clang-{}-{}-x86.tar.bz2'.format(build_number, host)
     98 
     99 
    100 def download_build(host, build_number, download_dir):
    101     filename = package_name(build_number, host)
    102     return download_file(host, build_number, filename, download_dir)
    103 
    104 
    105 def download_manifest(host, build_number, download_dir):
    106     filename = manifest_name(build_number)
    107     return download_file(host, build_number, filename, download_dir)
    108 
    109 
    110 def download_file(host, build_number, pkg_name, download_dir):
    111     url_base = 'https://android-build-uber.corp.google.com'
    112     path = 'builds/{branch}-{build_host}-{build_name}/{build_num}'.format(
    113         branch=BRANCH,
    114         build_host=host_to_build_host(host),
    115         build_name=build_name(host),
    116         build_num=build_number)
    117 
    118     url = '{}/{}/{}'.format(url_base, path, pkg_name)
    119 
    120     TIMEOUT = '60'  # In seconds.
    121     out_file_path = os.path.join(download_dir, pkg_name)
    122     with open(out_file_path, 'w') as out_file:
    123         print('Downloading {} to {}'.format(url, out_file_path))
    124         subprocess.check_call(
    125             ['sso_client', '--location', '--request_timeout', TIMEOUT, url],
    126             stdout=out_file)
    127     return out_file_path
    128 
    129 
    130 def extract_package(package, install_dir):
    131     cmd = ['tar', 'xf', package, '-C', install_dir]
    132     print('Extracting {}...'.format(package))
    133     subprocess.check_call(cmd)
    134 
    135 
    136 def update_clang(host, build_number, use_current_branch, download_dir, bug):
    137     host_tag = host + '-x86'
    138     prebuilt_dir = android_path('prebuilts/clang/host', host_tag)
    139     os.chdir(prebuilt_dir)
    140 
    141     if not use_current_branch:
    142         subprocess.check_call(
    143             ['repo', 'start', 'update-clang-{}'.format(build_number), '.'])
    144 
    145     package = download_build(host, build_number, download_dir)
    146     manifest = download_manifest(host, build_number, download_dir)
    147 
    148     install_subdir = 'clang-' + build_number
    149     extract_package(package, prebuilt_dir)
    150     shutil.copy(manifest, prebuilt_dir + '/' +  install_subdir)
    151 
    152     print('Adding files to index...')
    153     subprocess.check_call(['git', 'add', install_subdir])
    154 
    155     version_file_path = os.path.join(install_subdir, 'AndroidVersion.txt')
    156     with open(version_file_path) as version_file:
    157         version = version_file.read().strip()
    158 
    159     print('Committing update...')
    160     message_lines = [
    161         'Update prebuilt Clang to build {}.'.format(build_number),
    162         '',
    163         'Built from version {}.'.format(version),
    164     ]
    165     if bug is not None:
    166         message_lines.append('')
    167         message_lines.append('Bug: http://b/{}'.format(bug))
    168     message = '\n'.join(message_lines)
    169     subprocess.check_call(['git', 'commit', '-m', message])
    170 
    171 
    172 def main():
    173     args = ArgParser().parse_args()
    174 
    175     download_dir = os.path.realpath('.download')
    176     if os.path.isdir(download_dir):
    177         shutil.rmtree(download_dir)
    178     os.makedirs(download_dir)
    179 
    180     try:
    181         hosts = ('darwin', 'linux', 'windows')
    182         for host in hosts:
    183             update_clang(host, args.build, args.use_current_branch,
    184                          download_dir, args.bug)
    185     finally:
    186         shutil.rmtree(download_dir)
    187 
    188 
    189 if __name__ == '__main__':
    190     main()
    191