blob: c8c821c3ea068519f93972374441e9a42491e345 [file] [log] [blame]
#!/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
from tempfile import TemporaryDirectory
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)
LIBUNWIND_GLOB = (
'toolchains/llvm/prebuilt/*/lib64/clang/*/lib/linux/*/libunwind.a'
)
def unzip_single_directory(artifact, destination):
# Use cwd so that we can use rename without having to worry about crossing
# file systems.
with TemporaryDirectory(dir=os.getcwd()) as temp_dir:
cmd = [
'unzip',
artifact,
'-d',
temp_dir,
'*/sources/android/cpufeatures/*',
'*/sources/android/native_app_glue/*',
'*/sources/android/support/*',
'*/sources/cxx-stl/*',
'*/source.properties',
os.path.join('*', LIBUNWIND_GLOB),
]
check_call(cmd)
dirs = os.listdir(temp_dir)
assert len(dirs) == 1
ndk_dir = os.path.join(temp_dir, dirs[0])
for child in os.listdir(ndk_dir):
os.rename(os.path.join(ndk_dir, child),
os.path.join(destination, child))
def relocate_libunwind(install_dir):
unwinds = glob.glob(os.path.join(install_dir, LIBUNWIND_GLOB))
dest_base = os.path.join(install_dir, 'sources/cxx-stl/llvm-libc++/libs')
for libunwind in unwinds:
arch = os.path.basename(os.path.dirname(libunwind))
abi = {
'arm': 'armeabi-v7a',
'aarch64': 'arm64-v8a',
'i386': 'x86',
'x86_64': 'x86_64',
}[arch]
dest_dir = os.path.join(dest_base, abi)
dest = os.path.join(dest_dir, 'libunwind.a')
logger().info('Relocating %s to %s', libunwind, dest)
os.rename(libunwind, dest)
def install_new_release(branch, build, install_dir):
os.makedirs(install_dir)
artifact_pattern = 'android-ndk-*.zip'
logger().info('Fetching %s from %s (artifacts matching %s)', build, branch,
artifact_pattern)
fetch_artifact(branch, build, artifact_pattern)
artifacts = glob.glob('android-ndk-*.zip')
try:
assert len(artifacts) == 1
artifact = artifacts[0]
logger().info('Extracting release')
unzip_single_directory(artifact, install_dir)
relocate_libunwind(install_dir)
finally:
for artifact in artifacts:
os.unlink(artifact)
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}.
Bug: None
Test: treehugger
""").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)
commit(args.branch, args.build, install_dir)
if __name__ == '__main__':
main()