1#!/usr/bin/env python
2#
3# Copyright (C) 2016 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 RenderScript 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-master'
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_number', metavar='BUILD',
46            help='Build number to pull from the build server.')
47
48        self.add_argument(
49            '-a', '--android_branch', default=BRANCH,
50            help='The Android branch to pull from build server, default: ' + BRANCH + '.')
51
52        self.add_argument(
53            '-b', '--bug', type=int,
54            help='Bug to reference in commit message.')
55
56        self.add_argument(
57            '--use-current-branch', action='store_true',
58            help='Do not repo start a new branch for the update.')
59
60
61def host_to_build_host(host):
62    """Gets the build host name for an NDK host tag.
63
64    The Windows builds are done from Linux.
65    """
66    return {
67        'darwin': 'mac',
68        'linux': 'linux',
69        'windows': 'linux',
70    }[host]
71
72
73def build_name(host):
74    """Gets the build name for a given host.
75
76    The build name is either "linux" or "darwin", with any Windows builds
77    coming from "linux".
78    """
79    return {
80        'darwin': 'darwin',
81        'linux': 'linux',
82        'windows': 'linux',
83    }[host]
84
85
86def manifest_name(build_number):
87    """Returns the manifest file name for a given build.
88
89    >>> manifest_name('1234')
90    'manifest_1234.xml'
91    """
92    return 'manifest_{}.xml'.format(build_number)
93
94
95def package_name(build_number, host):
96    """Returns the file name for a given package configuration.
97
98    >>> package_name('1234', 'linux')
99    'renderscript-1234-linux-x86.tar.bz2'
100    """
101    return 'renderscript-{}-{}-x86.tar.bz2'.format(build_number, host)
102
103
104def download_build(host, build_number, android_branch, download_dir):
105    filename = package_name(build_number, host)
106    return download_file(host, build_number, android_branch, filename, download_dir)
107
108
109def download_manifest(host, build_number, android_branch, download_dir):
110    filename = manifest_name(build_number)
111    return download_file(host, build_number, android_branch, filename, download_dir)
112
113
114def download_file(host, build_number, android_branch, pkg_name, download_dir):
115    url_base = 'https://android-build-uber.corp.google.com'
116    path = 'builds/{build_branch}-{build_host}-{build_name}/{build_num}'.format(
117        build_branch=android_branch,
118        build_host=host_to_build_host(host),
119        build_name='renderscript',
120        build_num=build_number)
121
122    url = '{}/{}/{}'.format(url_base, path, pkg_name)
123
124    TIMEOUT = '60'  # In seconds.
125    out_file_path = os.path.join(download_dir, pkg_name)
126    with open(out_file_path, 'w') as out_file:
127        print('Downloading {} to {}'.format(url, out_file_path))
128        subprocess.check_call(
129            ['sso_client', '--location', '--request_timeout', TIMEOUT, url],
130            stdout=out_file)
131    return out_file_path
132
133
134def extract_package(package, install_dir):
135    cmd = ['tar', 'xf', package, '-C', install_dir]
136    print('Extracting {}...'.format(package))
137    subprocess.check_call(cmd)
138
139
140def update_renderscript(host, build_number, android_branch, use_current_branch, download_dir, bug):
141    host_tag = host + '-x86'
142    prebuilt_dir = android_path('prebuilts/renderscript/host', host_tag)
143    os.chdir(prebuilt_dir)
144
145    if not use_current_branch:
146        subprocess.check_call(
147            ['repo', 'start', 'update-renderscript-{}'.format(build_number), '.'])
148
149    package = download_build(host, build_number, android_branch, download_dir)
150    manifest = download_manifest(host, build_number, android_branch, download_dir)
151
152    install_subdir = 'current'
153    extract_package(package, prebuilt_dir)
154    shutil.rmtree(install_subdir)
155    shutil.move('renderscript-{}'.format(build_number), install_subdir)
156    shutil.copy(manifest, install_subdir)
157
158    print('Adding files to index...')
159    subprocess.check_call(['git', 'add', install_subdir])
160
161    print('Committing update...')
162    message_lines = [
163        'Update prebuilt RenderScript to build {}.'.format(build_number),
164        '',
165        'Built from {build_branch}, build {build_number}.'.format(
166            build_branch=android_branch,
167            build_number=build_number),
168    ]
169    if bug is not None:
170        message_lines.append('')
171        message_lines.append('Bug: http://b/{}'.format(bug))
172    message = '\n'.join(message_lines)
173    subprocess.check_call(['git', 'commit', '-m', message])
174
175
176def main():
177    args = ArgParser().parse_args()
178
179    download_dir = os.path.realpath('.download')
180    if os.path.isdir(download_dir):
181        shutil.rmtree(download_dir)
182    os.makedirs(download_dir)
183
184    try:
185        hosts = ('darwin', 'linux', 'windows')
186        for host in hosts:
187            update_renderscript(host, args.build_number, args.android_branch,
188                                args.use_current_branch, download_dir, args.bug)
189    finally:
190        shutil.rmtree(download_dir)
191
192
193if __name__ == '__main__':
194    main()
195