blob: c8c821c3ea068519f93972374441e9a42491e345 [file] [log] [blame]
Dan Albert74cf8ec2016-04-25 16:29:11 -07001#!/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#
17import argparse
18import glob
19import logging
20import os
21import shutil
22import subprocess
Dan Albert2e1bb712021-03-18 16:49:39 -070023from tempfile import TemporaryDirectory
Dan Albert74cf8ec2016-04-25 16:29:11 -070024import textwrap
25
26
27THIS_DIR = os.path.realpath(os.path.dirname(__file__))
28
29
30def logger():
31 return logging.getLogger(__name__)
32
33
34def check_call(cmd):
35 logger().debug('Running `%s`', ' '.join(cmd))
36 subprocess.check_call(cmd)
37
38
Dan Albert260ec6d2017-12-11 11:41:18 -080039def remove(path):
40 logger().debug('remove `%s`', path)
41 os.remove(path)
42
43
Dan Albert74cf8ec2016-04-25 16:29:11 -070044def fetch_artifact(branch, build, pattern):
45 fetch_artifact_path = '/google/data/ro/projects/android/fetch_artifact'
46 cmd = [fetch_artifact_path, '--branch', branch, '--target=linux',
47 '--bid', build, pattern]
48 check_call(cmd)
49
50
51def api_str(api_level):
52 return 'android-{}'.format(api_level)
53
54
55def start_branch(build):
56 branch_name = 'update-' + (build or 'latest')
57 logger().info('Creating branch %s', branch_name)
58 check_call(['repo', 'start', branch_name, '.'])
59
60
61def remove_old_release(install_dir):
62 if os.path.exists(os.path.join(install_dir, '.git')):
63 logger().info('Removing old install directory "%s"', install_dir)
64 check_call(['git', 'rm', '-rf', install_dir])
65
66 # Need to check again because git won't remove directories if they have
67 # non-git files in them.
68 if os.path.exists(install_dir):
69 shutil.rmtree(install_dir)
70
71
Dan Albertea7777b2021-03-19 12:50:04 -070072LIBUNWIND_GLOB = (
73 'toolchains/llvm/prebuilt/*/lib64/clang/*/lib/linux/*/libunwind.a'
74)
75
76
Dan Albert2e1bb712021-03-18 16:49:39 -070077def unzip_single_directory(artifact, destination):
78 # Use cwd so that we can use rename without having to worry about crossing
79 # file systems.
80 with TemporaryDirectory(dir=os.getcwd()) as temp_dir:
81 cmd = [
82 'unzip',
83 artifact,
84 '-d',
85 temp_dir,
86 '*/sources/android/cpufeatures/*',
87 '*/sources/android/native_app_glue/*',
88 '*/sources/android/support/*',
89 '*/sources/cxx-stl/*',
90 '*/source.properties',
Dan Albertea7777b2021-03-19 12:50:04 -070091 os.path.join('*', LIBUNWIND_GLOB),
Dan Albert2e1bb712021-03-18 16:49:39 -070092 ]
93 check_call(cmd)
94
95 dirs = os.listdir(temp_dir)
96 assert len(dirs) == 1
97 ndk_dir = os.path.join(temp_dir, dirs[0])
98 for child in os.listdir(ndk_dir):
99 os.rename(os.path.join(ndk_dir, child),
100 os.path.join(destination, child))
101
102
Dan Albertea7777b2021-03-19 12:50:04 -0700103def relocate_libunwind(install_dir):
104 unwinds = glob.glob(os.path.join(install_dir, LIBUNWIND_GLOB))
105 dest_base = os.path.join(install_dir, 'sources/cxx-stl/llvm-libc++/libs')
106 for libunwind in unwinds:
107 arch = os.path.basename(os.path.dirname(libunwind))
108 abi = {
109 'arm': 'armeabi-v7a',
110 'aarch64': 'arm64-v8a',
111 'i386': 'x86',
112 'x86_64': 'x86_64',
113 }[arch]
114 dest_dir = os.path.join(dest_base, abi)
115 dest = os.path.join(dest_dir, 'libunwind.a')
116 logger().info('Relocating %s to %s', libunwind, dest)
117 os.rename(libunwind, dest)
118
119
Dan Albert74cf8ec2016-04-25 16:29:11 -0700120def install_new_release(branch, build, install_dir):
121 os.makedirs(install_dir)
122
Dan Albert2e1bb712021-03-18 16:49:39 -0700123 artifact_pattern = 'android-ndk-*.zip'
Dan Albert74cf8ec2016-04-25 16:29:11 -0700124 logger().info('Fetching %s from %s (artifacts matching %s)', build, branch,
125 artifact_pattern)
126 fetch_artifact(branch, build, artifact_pattern)
Dan Albert2e1bb712021-03-18 16:49:39 -0700127 artifacts = glob.glob('android-ndk-*.zip')
Dan Albert74cf8ec2016-04-25 16:29:11 -0700128 try:
129 assert len(artifacts) == 1
130 artifact = artifacts[0]
131
132 logger().info('Extracting release')
Dan Albert2e1bb712021-03-18 16:49:39 -0700133 unzip_single_directory(artifact, install_dir)
Dan Albertea7777b2021-03-19 12:50:04 -0700134 relocate_libunwind(install_dir)
Dan Albert74cf8ec2016-04-25 16:29:11 -0700135 finally:
136 for artifact in artifacts:
137 os.unlink(artifact)
138
139
Dan Albert74cf8ec2016-04-25 16:29:11 -0700140def commit(branch, build, install_dir):
141 logger().info('Making commit')
142 check_call(['git', 'add', install_dir])
143 message = textwrap.dedent("""\
144 Update NDK prebuilts to build {build}.
145
Dan Albertf3fe50d2020-07-15 16:46:27 -0700146 Taken from branch {branch}.
147
148 Bug: None
149 Test: treehugger
150 """).format(branch=branch, build=build)
Dan Albert74cf8ec2016-04-25 16:29:11 -0700151 check_call(['git', 'commit', '-m', message])
152
153
154def get_args():
155 parser = argparse.ArgumentParser()
156 parser.add_argument(
157 '-b', '--branch', default='master-ndk',
158 help='Branch to pull build from.')
159 parser.add_argument(
160 'major_release', help='Major release being installed, e.g. "r11".')
161 parser.add_argument('--build', required=True, help='Build number to pull.')
162 parser.add_argument(
163 '--use-current-branch', action='store_true',
164 help='Perform the update in the current branch. Do not repo start.')
165 parser.add_argument(
Dan Albert7c75aef2017-09-18 14:38:38 -0700166 '-v', '--verbose', action='count', default=0,
167 help='Increase output verbosity.')
Dan Albert74cf8ec2016-04-25 16:29:11 -0700168 return parser.parse_args()
169
170
171def main():
172 os.chdir(THIS_DIR)
173
174 args = get_args()
175 verbose_map = (logging.WARNING, logging.INFO, logging.DEBUG)
176 verbosity = args.verbose
177 if verbosity > 2:
178 verbosity = 2
179 logging.basicConfig(level=verbose_map[verbosity])
180
181 install_dir = os.path.realpath(args.major_release)
182
183 if not args.use_current_branch:
184 start_branch(args.build)
185 remove_old_release(install_dir)
186 install_new_release(args.branch, args.build, install_dir)
Dan Albert74cf8ec2016-04-25 16:29:11 -0700187 commit(args.branch, args.build, install_dir)
188
189
190if __name__ == '__main__':
191 main()