blob: e1bdb042ec849eaffbc65a053088ad4273549527 [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.
#
"""Update the NDK platform prebuilts from the build server."""
import argparse
import logging
import os
import textwrap
def logger():
"""Returns the module logger."""
return logging.getLogger(__name__)
def check_call(cmd):
"""subprocess.check_call with logging."""
import subprocess
logger().debug('check_call `%s`', ' '.join(cmd))
subprocess.check_call(cmd)
def rmtree(path):
"""shutil.rmtree with logging."""
import shutil
logger().debug('rmtree %s', path)
shutil.rmtree(path)
def makedirs(path):
"""os.makedirs with logging."""
logger().debug('mkdir -p %s', path)
os.makedirs(path)
def remove(path):
"""os.remove with logging."""
logger().debug('rm %s', path)
os.remove(path)
def rename(src, dst):
"""os.rename with logging."""
logger().debug('mv %s %s', src, dst)
os.rename(src, dst)
def fetch_artifact(branch, target, build, pattern):
"""Fetches an artifact from the build server."""
fetch_artifact_path = '/google/data/ro/projects/android/fetch_artifact'
cmd = [fetch_artifact_path, '--branch', branch, '--target=' + target,
'--bid', build, pattern]
check_call(cmd)
# Fetch artifact dumps crap to the working directory.
remove('.fetch_artifact2.dat')
def remove_unwanted_platforms(install_path, remove_platforms):
"""Removes platforms that should not be checked in."""
for platform in remove_platforms:
platform_path = os.path.join(
install_path, 'platforms/android-{}'.format(platform))
if os.path.exists(platform_path):
rmtree(platform_path)
# The android-current platform is actually the future platform version (not
# even assigned to a codename), which should not be included in the NDK.
current_platform = os.path.join(install_path, 'platforms/android-current')
rmtree(current_platform)
rel_platform = os.path.join(install_path, 'platforms/android-REL')
if os.path.exists(rel_platform):
rmtree(rel_platform)
def rename_codenamed_releases(install_path, rename_codenames):
"""Rename codenamed releases."""
for codename, new_name in rename_codenames:
codename_path = os.path.join(
install_path, 'platforms/android-' + codename)
new_name_path = os.path.join(
install_path, 'platforms/android-' + new_name)
if os.path.exists(new_name_path):
raise RuntimeError(
'Could not rename android-{0} to android-{1} because '
'android-{1} already exists.'.format(codename, new_name))
rename(codename_path, new_name_path)
def kv_arg_pair(arg):
"""Parses a key/value argument pair."""
error_msg = 'Argument must be in format key=value, got ' + arg
try:
key, value = arg.split('=')
except ValueError:
raise argparse.ArgumentTypeError(error_msg)
if key == '' or value == '':
raise argparse.ArgumentTypeError(error_msg)
return key, value
def parse_args():
"""Parses and returns command line arguments."""
parser = argparse.ArgumentParser()
download_group = parser.add_mutually_exclusive_group()
download_group.add_argument(
'--download', action='store_true', default=True,
help='Fetch artifacts from the build server. BUILD is a build number.')
download_group.add_argument(
'--no-download', action='store_false', dest='download',
help=('Do not download build artifacts. BUILD points to a local '
'artifact.'))
parser.add_argument(
'build', metavar='BUILD_OR_ARTIFACT',
help=('Build number to pull from the build server, or a path to a '
'local artifact'))
parser.add_argument(
'--branch', default='aosp-master',
help='Branch to pull from the build server.')
parser.add_argument(
'-b', '--bug', default='None', help='Bug URL for commit message.')
parser.add_argument(
'--use-current-branch', action='store_true',
help='Do not repo start a new branch for the update.')
parser.add_argument(
'--remove-platform', action='append', default=[],
help='Remove platforms directories.')
parser.add_argument(
'--rename-codename', action='append', type=kv_arg_pair, default=[],
help='Rename codename platform. Example: --rename-codename O=26.')
return parser.parse_args()
def main():
"""Program entry point."""
logging.basicConfig(level=logging.DEBUG)
args = parse_args()
if args.download:
build = args.build
branch_name_suffix = build
else:
package = os.path.realpath(args.build)
branch_name_suffix = 'local'
logger().info('Using local artifact at %s', package)
os.chdir(os.path.realpath(os.path.dirname(__file__)))
if not args.use_current_branch:
branch_name = 'update-platform-' + branch_name_suffix
check_call(['repo', 'start', branch_name, '.'])
install_path = 'platform'
check_call(['git', 'rm', '-r', '--ignore-unmatch', install_path])
if os.path.exists(install_path):
rmtree(install_path)
makedirs(install_path)
if args.download:
fetch_artifact(args.branch, 'ndk', build, 'ndk_platform.tar.bz2')
package = 'ndk_platform.tar.bz2'
check_call(['tar', 'xf', package, '--strip-components=1', '-C',
install_path])
if args.download:
remove(package)
# It's easier to rearrange the package here than it is in the NDK's build.
# NOTICE is in the package root by convention, but we don't actually want
# this whole package to be the installed sysroot in the NDK. We have
# $INSTALL_DIR/sysroot and $INSTALL_DIR/platforms. $INSTALL_DIR/sysroot
# will be installed to $NDK/sysroot, but $INSTALL_DIR/platforms is used as
# input to Platforms. Shift the NOTICE into the sysroot directory.
rename(os.path.join(install_path, 'NOTICE'),
os.path.join(install_path, 'sysroot/NOTICE'))
remove_unwanted_platforms(install_path, args.remove_platform)
rename_codenamed_releases(install_path, args.rename_codename)
check_call(['git', 'add', install_path])
if args.download:
update_msg = 'to build {}'.format(build)
else:
update_msg = 'with local artifact'
message = textwrap.dedent("""\
Update NDK platform prebuilts {}.
Test: ndk/checkbuild.py && ndk/run_tests.py
Bug: {}
""".format(update_msg, args.bug))
check_call(['git', 'commit', '-m', message])
if __name__ == '__main__':
main()