#!/usr/bin/env python
#
# Copyright (C) 2016 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import argparse
import glob
import logging
import os
import shutil
import subprocess
import textwrap
THIS_DIR = os.path.realpath(os.path.dirname(__file__))
def logger():
return logging.getLogger(__name__)
def check_call(cmd):
logger().debug('Running `%s`', ' '.join(cmd))
subprocess.check_call(cmd)
def remove(path):
logger().debug('remove `%s`', path)
os.remove(path)
def fetch_artifact(branch, build, pattern):
fetch_artifact_path = '/google/data/ro/projects/android/fetch_artifact'
cmd = [fetch_artifact_path, '--branch', branch, '--target=linux',
'--bid', build, pattern]
check_call(cmd)
def api_str(api_level):
return 'android-{}'.format(api_level)
def start_branch(build):
branch_name = 'update-' + (build or 'latest')
logger().info('Creating branch %s', branch_name)
check_call(['repo', 'start', branch_name, '.'])
def remove_old_release(install_dir):
if os.path.exists(os.path.join(install_dir, '.git')):
logger().info('Removing old install directory "%s"', install_dir)
check_call(['git', 'rm', '-rf', install_dir])
# Need to check again because git won't remove directories if they have
# non-git files in them.
if os.path.exists(install_dir):
shutil.rmtree(install_dir)
def install_new_release(branch, build, install_dir):
os.makedirs(install_dir)
artifact_pattern = 'android-ndk-*.tar.bz2'
logger().info('Fetching %s from %s (artifacts matching %s)', build, branch,
artifact_pattern)
fetch_artifact(branch, build, artifact_pattern)
artifacts = glob.glob('android-ndk-*.tar.bz2')
try:
assert len(artifacts) == 1
artifact = artifacts[0]
logger().info('Extracting release')
cmd = ['tar', 'xf', artifact, '-C', install_dir, '--wildcards',
'--strip-components=1', '*/platforms', '*/sources',
'*/source.properties']
check_call(cmd)
finally:
for artifact in artifacts:
os.unlink(artifact)
def remove_unneeded_files(install_dir):
for path, _dirs, files in os.walk(os.path.join(install_dir, 'platforms')):
for file_name in files:
if file_name.endswith('.so'):
file_path = os.path.join(path, file_name)
remove(file_path)
for path, _dirs, files in os.walk(os.path.join(install_dir, 'sources')):
for file_name in files:
if file_name == 'Android.bp':
file_path = os.path.join(path, file_name)
remove(file_path)
def make_symlinks(install_dir):
old_dir = os.getcwd()
os.chdir(os.path.join(THIS_DIR, install_dir, 'platforms'))
first_api = 9
first_lp64_api = 21
for api in xrange(first_api, first_lp64_api):
if not os.path.exists(api_str(api)):
continue
for arch in ('arch-arm64', 'arch-mips64', 'arch-x86_64'):
src = os.path.join('..', api_str(first_lp64_api), arch)
dst = os.path.join(api_str(api), arch)
if os.path.islink(dst):
os.unlink(dst)
os.symlink(src, dst)
os.chdir(old_dir)
def commit(branch, build, install_dir):
logger().info('Making commit')
check_call(['git', 'add', install_dir])
message = textwrap.dedent("""\
Update NDK prebuilts to build {build}.
Taken from branch {branch}.""").format(branch=branch, build=build)
check_call(['git', 'commit', '-m', message])
def get_args():
parser = argparse.ArgumentParser()
parser.add_argument(
'-b', '--branch', default='master-ndk',
help='Branch to pull build from.')
parser.add_argument(
'major_release', help='Major release being installed, e.g. "r11".')
parser.add_argument('--build', required=True, help='Build number to pull.')
parser.add_argument(
'--use-current-branch', action='store_true',
help='Perform the update in the current branch. Do not repo start.')
parser.add_argument(
'-v', '--verbose', action='count', default=0,
help='Increase output verbosity.')
return parser.parse_args()
def main():
os.chdir(THIS_DIR)
args = get_args()
verbose_map = (logging.WARNING, logging.INFO, logging.DEBUG)
verbosity = args.verbose
if verbosity > 2:
verbosity = 2
logging.basicConfig(level=verbose_map[verbosity])
install_dir = os.path.realpath(args.major_release)
if not args.use_current_branch:
start_branch(args.build)
remove_old_release(install_dir)
install_new_release(args.branch, args.build, install_dir)
remove_unneeded_files(install_dir)
make_symlinks(install_dir)
commit(args.branch, args.build, install_dir)
if __name__ == '__main__':
main()