blob: 249ac963e5bcf02333e475c6116ee98522490fa6 [file] [log] [blame]
Alan Viverette95f6d362017-04-06 09:40:50 -04001#!/usr/bin/python
2
Alan Viverettecd3de262017-08-14 09:51:30 -04003# This script is used to update platform SDK prebuilts, Support Library, and a variety of other
4# prebuilt libraries used by Android's Makefile builds. For details on how to use this script,
5# visit go/update-prebuilts.
Alan Viverette95f6d362017-04-06 09:40:50 -04006import os, sys, getopt, zipfile, re
Alan Viveretted4527e62017-05-11 15:03:25 -04007import argparse
8import subprocess
Alan Viverette95f6d362017-04-06 09:40:50 -04009from shutil import copyfile, rmtree
Alan Viveretted4527e62017-05-11 15:03:25 -040010from distutils.version import LooseVersion
Alan Viverette95f6d362017-04-06 09:40:50 -040011
Alan Viverette45837092017-05-12 14:50:53 -040012current_path = 'current'
13system_path = 'system_current'
Alan Viverette3e57a4a2017-08-11 15:49:47 -040014support_dir = os.path.join(current_path, 'support')
15extras_dir = os.path.join(current_path, 'extras')
Alan Viverette95f6d362017-04-06 09:40:50 -040016
Alan Viverettecd3de262017-08-14 09:51:30 -040017# See go/fetch_artifact for details on this script.
Alan Viveretted4527e62017-05-11 15:03:25 -040018FETCH_ARTIFACT = '/google/data/ro/projects/android/fetch_artifact'
19
Alan Viverette95f6d362017-04-06 09:40:50 -040020# Does not import support-v4, which is handled as a separate Android.mk (../support-v4) to
21# statically include dependencies. Similarly, the support-v13 module is imported as
22# support-v13-nodeps and then handled as a separate Android.mk (../support-v13) to statically
23# include dependencies.
24maven_to_make = {
25 'animated-vector-drawable': ['android-support-animatedvectordrawable', 'graphics/drawable'],
Alan Viverette0aaa6252017-05-12 11:33:52 -040026 'appcompat-v7': ['android-support-v7-appcompat-nodeps', 'v7/appcompat'],
Alan Viverette95f6d362017-04-06 09:40:50 -040027 'cardview-v7': ['android-support-v7-cardview', 'v7/cardview'],
28 'customtabs': ['android-support-customtabs', 'customtabs'],
29 'design': ['android-support-design', 'design'],
30 'exifinterface': ['android-support-exifinterface', 'exifinterface'],
31 'gridlayout-v7': ['android-support-v7-gridlayout', 'v7/gridlayout'],
32 'leanback-v17': ['android-support-v17-leanback', 'v17/leanback'],
33 'mediarouter-v7': ['android-support-v7-mediarouter', 'v7/mediarouter'],
34 'multidex': ['android-support-multidex', 'multidex/library'],
35 'multidex-instrumentation': ['android-support-multidex-instrumentation', 'multidex/instrumentation'],
36 'palette-v7': ['android-support-v7-palette', 'v7/palette'],
37 'percent': ['android-support-percent', 'percent'],
38 'preference-leanback-v17': ['android-support-v17-preference-leanback', 'v17/preference-leanback'],
39 'preference-v14': ['android-support-v14-preference', 'v14/preference'],
40 'preference-v7': ['android-support-v7-preference', 'v7/preference'],
41 'recommendation': ['android-support-recommendation', 'recommendation'],
42 'recyclerview-v7': ['android-support-v7-recyclerview', 'v7/recyclerview'],
43 'support-annotations': ['android-support-annotations', 'annotations'],
44 'support-compat': ['android-support-compat', 'compat'],
45 'support-core-ui': ['android-support-core-ui', 'core-ui'],
46 'support-core-utils': ['android-support-core-utils', 'core-utils'],
47 'support-dynamic-animation': ['android-support-dynamic-animation', 'dynamic-animation'],
48 'support-emoji': ['android-support-emoji', 'emoji'],
49 'support-emoji-appcompat': ['android-support-emoji-appcompat', 'emoji-appcompat'],
50 'support-emoji-bundled': ['android-support-emoji-bundled', 'emoji-bundled'],
51 'support-fragment': ['android-support-fragment', 'fragment'],
52 'support-media-compat': ['android-support-media-compat', 'media-compat'],
53 'support-tv-provider': ['android-support-tv-provider', 'tv-provider'],
Alan Viverette0aaa6252017-05-12 11:33:52 -040054 'support-v13': ['android-support-v13-nodeps', 'v13'],
Alan Viverette95f6d362017-04-06 09:40:50 -040055 'support-vector-drawable': ['android-support-vectordrawable', 'graphics/drawable'],
56 'transition': ['android-support-transition', 'transition'],
Alan Viverette3e57a4a2017-08-11 15:49:47 -040057 'wear': ['android-support-wear', 'wear'],
58 'constraint-layout': ['android-support-constraint-layout', 'constraint-layout'],
59 'constraint-layout-solver': ['android-support-constraint-layout-solver', 'constraint-layout-solver']
Alan Viverette95f6d362017-04-06 09:40:50 -040060}
61
62# Always remove these files.
63blacklist_files = [
64 'annotations.zip',
65 'public.txt',
66 'R.txt',
Alan Viverette44ad4e42017-08-09 17:45:00 -040067 'AndroidManifest.xml',
68 'noto-emoji-compat-java.jar'
Alan Viverette95f6d362017-04-06 09:40:50 -040069]
70
Alan Viverette44ad4e42017-08-09 17:45:00 -040071artifact_pattern = re.compile(r"^(.+?)-(\d+\.\d+\.\d+(?:-\w+\d+)?(?:-[\d.]+)*)\.(jar|aar)$")
Alan Viverette95f6d362017-04-06 09:40:50 -040072
73
74def touch(fname, times=None):
75 with open(fname, 'a'):
76 os.utime(fname, times)
77
78
Alan Viverette45837092017-05-12 14:50:53 -040079def path(*path_parts):
80 return reduce((lambda x, y: os.path.join(x, y)), path_parts)
81
82
Alan Viverettecd3de262017-08-14 09:51:30 -040083def flatten(list):
84 return reduce((lambda x, y: "%s %s" % (x, y)), list)
85
86
Alan Viverette45837092017-05-12 14:50:53 -040087def rm(path):
88 if os.path.isdir(path):
89 rmtree(path)
90 elif os.path.exists(path):
91 os.remove(path)
92
93
94def mv(src_path, dst_path):
Alan Viverette3e57a4a2017-08-11 15:49:47 -040095 if os.path.exists(dst_path):
Alan Viverettecd3de262017-08-14 09:51:30 -040096 rm(dst_path)
Alan Viverette3e57a4a2017-08-11 15:49:47 -040097 if not os.path.exists(os.path.dirname(dst_path)):
98 os.makedirs(os.path.dirname(dst_path))
Alan Viverette45837092017-05-12 14:50:53 -040099 os.rename(src_path, dst_path)
100
101
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400102def detect_artifacts(repo_dir):
Alan Viveretted4527e62017-05-11 15:03:25 -0400103 maven_lib_info = {}
104
Alan Viverette5bfe05b2017-06-06 14:21:29 -0400105 # Find the latest revision for each artifact.
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400106 for root, dirs, files in os.walk(repo_dir):
Alan Viverette95f6d362017-04-06 09:40:50 -0400107 for file in files:
108 matcher = artifact_pattern.match(file)
109 if matcher:
110 maven_lib_name = matcher.group(1)
Alan Viveretted4527e62017-05-11 15:03:25 -0400111 maven_lib_vers = LooseVersion(matcher.group(2))
Alan Viverette95f6d362017-04-06 09:40:50 -0400112
113 if maven_lib_name in maven_to_make:
Alan Viveretted4527e62017-05-11 15:03:25 -0400114 if maven_lib_name not in maven_lib_info \
115 or maven_lib_vers > maven_lib_info[maven_lib_name][0]:
116 maven_lib_info[maven_lib_name] = [maven_lib_vers, root, file]
Alan Viverette95f6d362017-04-06 09:40:50 -0400117
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400118 return maven_lib_info
119
120
121def transform_maven_repo(repo_dir, update_dir, use_make_dir=True):
122 maven_lib_info = detect_artifacts(repo_dir)
123
124 cwd = os.getcwd()
125
126 # Use a temporary working directory.
127 working_dir = os.path.join(cwd, 'support_tmp')
128 if os.path.exists(working_dir):
129 rmtree(working_dir)
130 os.mkdir(working_dir)
131
Alan Viveretted4527e62017-05-11 15:03:25 -0400132 for info in maven_lib_info.values():
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400133 transform_maven_lib(working_dir, info[1], info[2], use_make_dir)
Alan Viverette95f6d362017-04-06 09:40:50 -0400134
135 # Replace the old directory.
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400136 output_dir = os.path.join(cwd, update_dir)
137 mv(working_dir, output_dir)
Alan Viverette95f6d362017-04-06 09:40:50 -0400138
Alan Viveretted4527e62017-05-11 15:03:25 -0400139
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400140def transform_maven_lib(working_dir, root, file, use_make_dir):
Alan Viveretted4527e62017-05-11 15:03:25 -0400141 matcher = artifact_pattern.match(file)
142 maven_lib_name = matcher.group(1)
143 maven_lib_vers = matcher.group(2)
144 maven_lib_type = matcher.group(3)
145
146 make_lib_name = maven_to_make[maven_lib_name][0]
147 make_dir_name = maven_to_make[maven_lib_name][1]
148 artifact_file = os.path.join(root, file)
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400149 target_dir = os.path.join(working_dir, make_dir_name) if use_make_dir else working_dir
Alan Viveretted4527e62017-05-11 15:03:25 -0400150 if not os.path.exists(target_dir):
151 os.makedirs(target_dir)
152
153 if maven_lib_type == "aar":
154 process_aar(artifact_file, target_dir, make_lib_name)
155 else:
156 target_file = os.path.join(target_dir, make_lib_name + ".jar")
157 os.rename(artifact_file, target_file)
158
159 print maven_lib_vers, ":", maven_lib_name, "->", make_lib_name
160
Alan Viverette95f6d362017-04-06 09:40:50 -0400161
162def process_aar(artifact_file, target_dir, make_lib_name):
163 # Extract AAR file to target_dir.
164 with zipfile.ZipFile(artifact_file) as zip:
165 zip.extractall(target_dir)
166
167 # Rename classes.jar to match the make artifact
168 classes_jar = os.path.join(target_dir, "classes.jar")
169 if os.path.exists(classes_jar):
170 # If it has resources, it needs a libs dir.
171 res_dir = os.path.join(target_dir, "res")
172 if os.path.exists(res_dir) and os.listdir(res_dir):
173 libs_dir = os.path.join(target_dir, "libs")
174 if not os.path.exists(libs_dir):
175 os.mkdir(libs_dir)
176 else:
177 libs_dir = target_dir
178 target_jar = os.path.join(libs_dir, make_lib_name + ".jar")
179 os.rename(classes_jar, target_jar)
180
181 # Remove or preserve empty dirs.
182 for root, dirs, files in os.walk(target_dir):
183 for dir in dirs:
184 dir_path = os.path.join(root, dir)
185 if not os.listdir(dir_path):
186 os.rmdir(dir_path)
187
188 # Remove top-level cruft.
189 for file in blacklist_files:
190 file_path = os.path.join(target_dir, file)
191 if os.path.exists(file_path):
192 os.remove(file_path)
193
Alan Viverettef17c9402017-07-19 12:57:40 -0400194
Alan Viverettecd3de262017-08-14 09:51:30 -0400195def fetch_artifact(target, build_id, artifact_path):
Alan Viverette45837092017-05-12 14:50:53 -0400196 print 'Fetching %s from %s...' % (artifact_path, target)
Alan Viverettecd3de262017-08-14 09:51:30 -0400197 fetch_cmd = [FETCH_ARTIFACT, '--bid', str(build_id), '--target', target, artifact_path]
Alan Viverette45837092017-05-12 14:50:53 -0400198 try:
Alan Viverettecd3de262017-08-14 09:51:30 -0400199 subprocess.check_output(fetch_cmd, stderr=subprocess.STDOUT)
Alan Viverette45837092017-05-12 14:50:53 -0400200 except subprocess.CalledProcessError:
Alan Viverettecd3de262017-08-14 09:51:30 -0400201 print >> sys.stderr, 'FAIL: Unable to retrieve %s artifact for build ID %d' % (artifact_path, build_id)
Alan Viverette45837092017-05-12 14:50:53 -0400202 return None
203 return artifact_path
204
205
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400206def fetch_and_extract(target, build_id, file):
207 artifact_path = fetch_artifact(target, build_id, file)
Alan Viverette45837092017-05-12 14:50:53 -0400208 if not artifact_path:
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400209 return None
Alan Viverette45837092017-05-12 14:50:53 -0400210
211 # Unzip the repo archive into a separate directory.
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400212 repo_dir = os.path.basename(artifact_path)[:-4]
Alan Viverette45837092017-05-12 14:50:53 -0400213 with zipfile.ZipFile(artifact_path) as zipFile:
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400214 zipFile.extractall(repo_dir)
215
216 return repo_dir
217
218
219def update_support(target, build_id):
Alan Viverettecd3de262017-08-14 09:51:30 -0400220 repo_file = 'top-of-tree-m2repository-%s.zip' % build_id
221 repo_dir = fetch_and_extract(target, build_id, repo_file)
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400222 if not repo_dir:
223 print >> sys.stderr, 'Failed to extract Support Library repository'
224 return
Alan Viverette45837092017-05-12 14:50:53 -0400225
226 # Transform the repo archive into a Makefile-compatible format.
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400227 transform_maven_repo(repo_dir, support_dir)
228
229
230def update_constraint(target, build_id):
231 layout_dir = fetch_and_extract(target, build_id, 'com.android.support.constraint-constraint-layout-%s.zip' % build_id)
232 solver_dir = fetch_and_extract(target, build_id, 'com.android.support.constraint-constraint-layout-solver-%s.zip' % build_id)
233 if not layout_dir or not solver_dir:
Alan Viverettecd3de262017-08-14 09:51:30 -0400234 return False
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400235
236 # Passing False here is an inelegant solution, but it means we can replace
237 # the top-level directory without worrying about other child directories.
238 transform_maven_repo(layout_dir, os.path.join(extras_dir, 'constraint-layout'), False)
239 transform_maven_repo(solver_dir, os.path.join(extras_dir, 'constraint-layout-solver'), False)
Alan Viverettecd3de262017-08-14 09:51:30 -0400240 return True
Alan Viverette45837092017-05-12 14:50:53 -0400241
242
243def extract_to(zip_file, paths, filename, parent_path):
244 zip_path = filter(lambda path: filename in path, paths)[0]
245 src_path = zip_file.extract(zip_path)
246 dst_path = path(parent_path, filename)
247 mv(src_path, dst_path)
248
249
Alan Viverettecd3de262017-08-14 09:51:30 -0400250def update_sdk_repo(target, build_id):
Alan Viverette45837092017-05-12 14:50:53 -0400251 platform = 'darwin' if 'mac' in target else 'linux'
Alan Viverettecd3de262017-08-14 09:51:30 -0400252 artifact_path = fetch_artifact(
253 target, build_id, 'sdk-repo-%s-platforms-%s.zip' % (platform, build_id))
Alan Viverette45837092017-05-12 14:50:53 -0400254 if not artifact_path:
Alan Viverettecd3de262017-08-14 09:51:30 -0400255 return False
Alan Viverette45837092017-05-12 14:50:53 -0400256
257 with zipfile.ZipFile(artifact_path) as zipFile:
258 paths = zipFile.namelist()
259
260 extract_to(zipFile, paths, 'android.jar', current_path)
261 extract_to(zipFile, paths, 'uiautomator.jar', current_path)
262 extract_to(zipFile, paths, 'framework.aidl', current_path)
263
264 # Unclear if this is actually necessary.
265 extract_to(zipFile, paths, 'framework.aidl', system_path)
Alan Viverettecd3de262017-08-14 09:51:30 -0400266 return True
Alan Viverette45837092017-05-12 14:50:53 -0400267
268
Alan Viverettecd3de262017-08-14 09:51:30 -0400269def update_system(target, build_id):
270 artifact_path = fetch_artifact(target, build_id, 'android_system.jar')
Alan Viverette45837092017-05-12 14:50:53 -0400271 if not artifact_path:
Alan Viverettecd3de262017-08-14 09:51:30 -0400272 return False
Alan Viverette45837092017-05-12 14:50:53 -0400273
274 mv(artifact_path, path(system_path, 'android.jar'))
Alan Viverettecd3de262017-08-14 09:51:30 -0400275 return True
276
277
278def append(text, more_text):
279 if text:
280 return "%s, %s" % (text, more_text)
281 return more_text
Alan Viverette45837092017-05-12 14:50:53 -0400282
Alan Viverette95f6d362017-04-06 09:40:50 -0400283
Alan Viveretted4527e62017-05-11 15:03:25 -0400284parser = argparse.ArgumentParser(
Alan Viverette45837092017-05-12 14:50:53 -0400285 description=('Update current prebuilts'))
Alan Viveretted4527e62017-05-11 15:03:25 -0400286parser.add_argument(
287 'buildId',
288 type=int,
Alan Viveretted4527e62017-05-11 15:03:25 -0400289 help='Build server build ID')
290parser.add_argument(
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400291 '-c', '--constraint', action="store_true",
292 help='If specified, updates only Constraint Layout')
293parser.add_argument(
Alan Viverette5bfe05b2017-06-06 14:21:29 -0400294 '-s', '--support', action="store_true",
295 help='If specified, updates only the Support Library')
Alan Viverette45837092017-05-12 14:50:53 -0400296parser.add_argument(
Alan Viverette5bfe05b2017-06-06 14:21:29 -0400297 '-p', '--platform', action="store_true",
298 help='If specified, updates only the Android Platform')
Alan Viveretted4527e62017-05-11 15:03:25 -0400299args = parser.parse_args()
300if not args.buildId:
301 parser.error("You must specify a build ID")
302 sys.exit(1)
Alan Viverettecd3de262017-08-14 09:51:30 -0400303if not (args.support or args.platform or args.constraint):
304 parser.error("You must specify at least one of --constraint, --support, or --platform")
305 sys.exit(1)
Alan Viveretted4527e62017-05-11 15:03:25 -0400306
307try:
308 # Make sure we don't overwrite any pending changes.
309 subprocess.check_call(['git', 'diff', '--quiet', '--', '**'])
310 subprocess.check_call(['git', 'diff', '--quiet', '--cached', '--', '**'])
311except subprocess.CalledProcessError:
312 print >> sys.stderr, "FAIL: There are uncommitted changes here; please revert or stash"
313 sys.exit(1)
314
315try:
Alan Viverettecd3de262017-08-14 09:51:30 -0400316 components = None
317 if args.constraint:
318 if update_constraint('studio', args.buildId):
319 components = append(components, 'Constraint Layout')
320 else:
321 sys.exit(1)
322 if args.support:
323 if update_support('support_library', args.buildId):
324 components = append(components, 'Support Library')
325 else:
326 sys.exit(1)
327 if args.platform:
328 if update_sdk_repo('sdk_phone_armv7-sdk_mac', args.buildId) \
329 and update_system('sdk_phone_armv7-sdk_mac', args.buildId):
330 components = append(components, 'platform SDK')
331 else:
332 sys.exit(1)
Alan Viveretted4527e62017-05-11 15:03:25 -0400333
334 # Commit all changes.
Alan Viverette45837092017-05-12 14:50:53 -0400335 subprocess.check_call(['git', 'add', current_path])
336 subprocess.check_call(['git', 'add', system_path])
Alan Viverettecd3de262017-08-14 09:51:30 -0400337 msg = "Import %s from build %s\n\n%s" % (components, args.buildId, flatten(sys.argv))
Alan Viveretted4527e62017-05-11 15:03:25 -0400338 subprocess.check_call(['git', 'commit', '-m', msg])
Alan Viverettecd3de262017-08-14 09:51:30 -0400339 print 'Remember to test this change before uploading it to Gerrit!'
Alan Viveretted4527e62017-05-11 15:03:25 -0400340
341finally:
342 # Revert all stray files, including the downloaded zip.
343 try:
344 with open(os.devnull, 'w') as bitbucket:
345 subprocess.check_call(['git', 'add', '-Af', '.'], stdout=bitbucket)
346 subprocess.check_call(
347 ['git', 'commit', '-m', 'COMMIT TO REVERT - RESET ME!!!'], stdout=bitbucket)
348 subprocess.check_call(['git', 'reset', '--hard', 'HEAD~1'], stdout=bitbucket)
349 except subprocess.CalledProcessError:
Alan Viverette44ad4e42017-08-09 17:45:00 -0400350 print >> sys.stderr, "ERROR: Failed cleaning up, manual cleanup required!!!"