You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
192 lines
5.7 KiB
192 lines
5.7 KiB
#!/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()
|