blob: 2ba927d533d8430c1a8a09cecb2b34ac9984917c [file] [log] [blame]
Alan Viverettef5cb0e62017-11-17 15:15:23 -05001#!/usr/bin/python3
Alan Viverette95f6d362017-04-06 09:40:50 -04002
Anvesh Renikindi18680e62022-10-26 19:15:50 +00003"""Updates prebuilt libraries used by Android builds.
4
5For details on how to use this script, visit go/update-prebuilts.
6"""
7import os
8import sys
9import zipfile
10import re
Alan Viveretted4527e62017-05-11 15:03:25 -040011import argparse
12import subprocess
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +000013import six
Anvesh Renikindi18680e62022-10-26 19:15:50 +000014import shlex
15
16from urllib import request
17from shutil import which
18from distutils.version import LooseVersion
19from pathlib import Path
20from maven import MavenLibraryInfo, GMavenArtifact, maven_path_for_artifact
21from buildserver import fetch_and_extract, fetch_artifacts, fetch_artifact, extract_artifact, \
22 parse_build_id
23from utils import print_e, append, cp, mv, rm
24
Alan Viverette95f6d362017-04-06 09:40:50 -040025
Alan Viverette45837092017-05-12 14:50:53 -040026current_path = 'current'
Anvesh Renikindi18680e62022-10-26 19:15:50 +000027framework_sdk_target = 'sdk'
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -040028androidx_dir = os.path.join(current_path, 'androidx')
Anvesh Renikindi18680e62022-10-26 19:15:50 +000029androidx_owners = os.path.join(androidx_dir, 'OWNERS')
30java_plugins_bp_path = os.path.join(androidx_dir, 'JavaPlugins.bp')
31test_mapping_file = os.path.join(androidx_dir, 'TEST_MAPPING')
Nick Anthonybac2fca2022-11-03 18:56:57 +000032compose_test_mapping_file = os.path.join(androidx_dir, 'm2repository/androidx/compose/TEST_MAPPING')
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +000033gmaven_dir = os.path.join(current_path, 'gmaven')
Alan Viverette3e57a4a2017-08-11 15:49:47 -040034extras_dir = os.path.join(current_path, 'extras')
Alan Viverettec1c32b62017-12-20 09:40:36 -050035buildtools_dir = 'tools'
Jeff Gaston553a4372018-03-29 18:34:22 -040036jetifier_dir = os.path.join(buildtools_dir, 'jetifier', 'jetifier-standalone')
Anton Hansson4bcebac2022-04-07 17:23:18 +010037repo_root_dir = Path(sys.argv[0]).resolve().parents[3]
Anvesh Renikindi18680e62022-10-26 19:15:50 +000038extension_sdk_finalization_cmd = '%s -r "{readme}" -b {bug} -f {extension_version} {build_id}' % (
Anton Hansson4bcebac2022-04-07 17:23:18 +010039 "packages/modules/common/tools/finalize_sdk.py"
40)
Anvesh Renikindi18680e62022-10-26 19:15:50 +000041temp_dir = os.path.join(os.getcwd(), 'support_tmp')
Jeff Gastona68a8d42018-03-23 14:00:13 -040042os.chdir(os.path.dirname(os.path.dirname(os.path.realpath(sys.argv[0]))))
43git_dir = os.getcwd()
44
Alan Viverette0723aff2021-08-31 17:07:47 +000045# Leave map blank to automatically populate name and path:
46# - Name format is MAVEN.replaceAll(':','_')
47# - Path format is MAVEN.replaceAll(':','/').replaceAll('.','/')
Alan Viverette95f6d362017-04-06 09:40:50 -040048maven_to_make = {
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -040049 # AndroidX
Anvesh Renikindi18680e62022-10-26 19:15:50 +000050 'androidx.benchmark:benchmark-macro': {},
51 'androidx.benchmark:benchmark-macro-junit4': {},
52 'androidx.benchmark:benchmark-common': {},
53 'androidx.benchmark:benchmark-junit4': {},
54 'androidx.tracing:tracing': {},
55 'androidx.tracing:tracing-perfetto': {},
56 'androidx.tracing:tracing-perfetto-binary': {},
57 'androidx.tracing:tracing-perfetto-common': {},
58 'androidx.tracing:tracing-ktx': {},
59 'androidx.slice:slice-builders': {},
60 'androidx.slice:slice-core': {},
61 'androidx.slice:slice-view': {},
62 'androidx.remotecallback:remotecallback': {},
63 'androidx.remotecallback:remotecallback-processor': {
64 'host': True
65 },
66 'androidx.versionedparcelable:versionedparcelable': {},
67 'androidx.vectordrawable:vectordrawable-animated': {},
68 'androidx.activity:activity': {},
69 'androidx.activity:activity-ktx': {},
70 'androidx.annotation:annotation': {
71 'host_and_device': True,
72 'extra-static-libs': {
73 'androidx.annotation_annotation-jvm'
74 }
75 },
76 'androidx.annotation:annotation-jvm': {
77 'host_and_device': True
78 },
79 'androidx.annotation:annotation-experimental': {},
80 'androidx.asynclayoutinflater:asynclayoutinflater': {},
81 'androidx.collection:collection': {
82 'extra-static-libs': {
83 'androidx.collection_collection-jvm'
84 }
85 },
86 'androidx.collection:collection-ktx': {},
87 'androidx.collection:collection-jvm': {},
88 'androidx.concurrent:concurrent-futures': {},
89 'androidx.concurrent:concurrent-listenablefuture-callback': {},
90 'androidx.concurrent:concurrent-listenablefuture': {},
91 'androidx.core:core': {},
92 'androidx.core:core-animation': {},
Johannes Gallmann33504562022-11-17 09:32:02 +000093 'androidx.core:core-animation-testing': {},
Anvesh Renikindi18680e62022-10-26 19:15:50 +000094 'androidx.core:core-ktx': {},
95 'androidx.core.uwb:uwb': {},
96 'androidx.core.uwb:uwb-rxjava3': {},
97 'androidx.contentpaging:contentpaging': {},
98 'androidx.coordinatorlayout:coordinatorlayout': {},
99 'androidx.legacy:legacy-support-core-ui': {},
100 'androidx.legacy:legacy-support-core-utils': {},
101 'androidx.cursoradapter:cursoradapter': {},
102 'androidx.browser:browser': {},
103 'androidx.customview:customview': {},
104 'androidx.customview:customview-poolingcontainer': {},
105 'androidx.documentfile:documentfile': {},
106 'androidx.drawerlayout:drawerlayout': {},
107 'androidx.dynamicanimation:dynamicanimation': {},
108 'androidx.emoji:emoji': {},
109 'androidx.emoji:emoji-appcompat': {},
110 'androidx.emoji:emoji-bundled': {},
111 'androidx.emoji2:emoji2': {},
112 'androidx.emoji2:emoji2-views-helper': {},
113 'androidx.exifinterface:exifinterface': {},
114 'androidx.fragment:fragment': {},
115 'androidx.fragment:fragment-ktx': {},
116 'androidx.heifwriter:heifwriter': {},
117 'androidx.interpolator:interpolator': {},
118 'androidx.loader:loader': {},
119 'androidx.media:media': {},
120 'androidx.media2:media2-player': {},
121 'androidx.media2:media2-session': {},
122 'androidx.media2:media2-common': {},
123 'androidx.media2:media2-exoplayer': {},
124 'androidx.media2:media2-widget': {},
125 'androidx.navigation:navigation-common': {},
126 'androidx.navigation:navigation-common-ktx': {},
127 'androidx.navigation:navigation-fragment': {},
128 'androidx.navigation:navigation-fragment-ktx': {},
129 'androidx.navigation:navigation-runtime': {},
130 'androidx.navigation:navigation-runtime-ktx': {},
131 'androidx.navigation:navigation-ui': {},
132 'androidx.navigation:navigation-ui-ktx': {},
133 'androidx.percentlayout:percentlayout': {},
134 'androidx.print:print': {},
135 'androidx.recommendation:recommendation': {},
136 'androidx.recyclerview:recyclerview-selection': {},
137 'androidx.savedstate:savedstate': {},
138 'androidx.savedstate:savedstate-ktx': {},
139 'androidx.slidingpanelayout:slidingpanelayout': {},
140 'androidx.swiperefreshlayout:swiperefreshlayout': {},
141 'androidx.textclassifier:textclassifier': {},
142 'androidx.transition:transition': {},
143 'androidx.tvprovider:tvprovider': {},
144 'androidx.legacy:legacy-support-v13': {},
145 'androidx.legacy:legacy-preference-v14': {},
146 'androidx.leanback:leanback': {},
147 'androidx.leanback:leanback-grid': {},
148 'androidx.leanback:leanback-preference': {},
149 'androidx.legacy:legacy-support-v4': {},
150 'androidx.appcompat:appcompat': {},
151 'androidx.appcompat:appcompat-resources': {},
152 'androidx.cardview:cardview': {},
153 'androidx.gridlayout:gridlayout': {},
154 'androidx.mediarouter:mediarouter': {},
155 'androidx.palette:palette': {},
156 'androidx.preference:preference': {},
157 'androidx.recyclerview:recyclerview': {},
158 'androidx.vectordrawable:vectordrawable': {},
159 'androidx.viewpager:viewpager': {},
160 'androidx.viewpager2:viewpager2': {},
161 'androidx.wear:wear': {},
162 'androidx.wear:wear-ongoing': {},
163 'androidx.javascriptengine:javascriptengine': {},
164 'androidx.webkit:webkit': {},
165 'androidx.biometric:biometric': {},
166 'androidx.autofill:autofill': {},
167 'androidx.appsearch:appsearch': {},
168 'androidx.appsearch:appsearch-builtin-types': {},
169 'androidx.appsearch:appsearch-compiler': {
170 'name': 'androidx.appsearch_appsearch-compiler',
171 'host': True
172 },
173 'androidx.appsearch:appsearch-local-storage': {
174 'name': 'androidx.appsearch_appsearch_local_storage'
175 },
176 'androidx.appsearch:appsearch-platform-storage': {},
177 'androidx.car.app:app': {},
178 'androidx.car.app:app-automotive': {},
179 'androidx.car.app:app-testing': {},
180 'androidx.startup:startup-runtime': {},
181 'androidx.window:window': {
182 'optional-uses-libs': {
183 'androidx.window.extensions',
184 'androidx.window.sidecar'
185 }
186 },
187 'androidx.resourceinspection:resourceinspection-annotation': {},
188 'androidx.profileinstaller:profileinstaller': {},
189 'androidx.test.uiautomator:uiautomator': {},
Aurimas Liutikas6e87bbf2021-07-30 10:04:05 -0700190
Alan Viverettef44e2f92021-08-31 17:26:26 +0000191 # AndroidX for Compose
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000192 'androidx.compose.compiler:compiler-hosted': {
193 'host': True
194 },
195 'androidx.compose.runtime:runtime': {},
196 'androidx.compose.runtime:runtime-saveable': {},
197 'androidx.compose.runtime:runtime-livedata': {},
198 'androidx.compose.foundation:foundation': {},
199 'androidx.compose.foundation:foundation-layout': {},
200 'androidx.compose.foundation:foundation-text': {},
201 'androidx.compose.ui:ui': {},
202 'androidx.compose.ui:ui-geometry': {},
203 'androidx.compose.ui:ui-graphics': {},
204 'androidx.compose.ui:ui-text': {},
205 'androidx.compose.ui:ui-tooling': {},
206 'androidx.compose.ui:ui-tooling-preview': {},
207 'androidx.compose.ui:ui-tooling-data': {},
208 'androidx.compose.ui:ui-unit': {},
209 'androidx.compose.ui:ui-util': {},
Jordan Demeulenaere606dca92022-07-29 16:09:28 +0200210 'androidx.compose.ui:ui-test': { },
211 'androidx.compose.ui:ui-test-junit4': { },
Jordan Demeulenaere76170242022-05-16 12:18:39 +0200212 'androidx.compose.ui:ui-test-manifest': { },
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000213 'androidx.compose.animation:animation-core': {},
214 'androidx.compose.animation:animation': {},
215 'androidx.compose.material:material-icons-core': {},
Jordan Demeulenaere606dca92022-07-29 16:09:28 +0200216 'androidx.compose.material:material-icons-extended': { },
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000217 'androidx.compose.material:material-ripple': {},
218 'androidx.compose.material:material': {},
219 'androidx.compose.material3:material3': {},
220 'androidx.activity:activity-compose': {},
Jordan Demeulenaere606dca92022-07-29 16:09:28 +0200221 'androidx.navigation:navigation-compose': { },
222 'androidx.lifecycle:lifecycle-viewmodel-compose': { },
Alan Viverettef44e2f92021-08-31 17:26:26 +0000223
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400224 # AndroidX for Multidex
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000225 'androidx.multidex:multidex': {},
226 'androidx.multidex:multidex-instrumentation': {},
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400227
228 # AndroidX for Constraint Layout
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000229 'androidx.constraintlayout:constraintlayout': {
230 'name': 'androidx-constraintlayout_constraintlayout'
231 },
232 'androidx.constraintlayout:constraintlayout-solver': {
233 'name': 'androidx-constraintlayout_constraintlayout-solver'
234 },
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400235
236 # AndroidX for Architecture Components
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000237 'androidx.arch.core:core-common': {},
238 'androidx.arch.core:core-runtime': {},
239 'androidx.lifecycle:lifecycle-common': {},
240 'androidx.lifecycle:lifecycle-common-java8': {},
241 'androidx.lifecycle:lifecycle-extensions': {},
242 'androidx.lifecycle:lifecycle-livedata': {},
243 'androidx.lifecycle:lifecycle-livedata-ktx': {},
244 'androidx.lifecycle:lifecycle-livedata-core': {},
245 'androidx.lifecycle:lifecycle-livedata-core-ktx': {},
246 'androidx.lifecycle:lifecycle-process': {},
247 'androidx.lifecycle:lifecycle-runtime': {},
248 'androidx.lifecycle:lifecycle-runtime-ktx': {},
249 'androidx.lifecycle:lifecycle-service': {},
250 'androidx.lifecycle:lifecycle-viewmodel': {},
251 'androidx.lifecycle:lifecycle-viewmodel-ktx': {},
252 'androidx.lifecycle:lifecycle-viewmodel-savedstate': {},
253 'androidx.paging:paging-common': {},
254 'androidx.paging:paging-common-ktx': {},
255 'androidx.paging:paging-runtime': {},
256 'androidx.sqlite:sqlite': {},
257 'androidx.sqlite:sqlite-framework': {},
258 'androidx.room:room-common': {
259 'host_and_device': True
260 },
261 'androidx.room:room-compiler': {
262 'host': True,
263 'extra-static-libs': {
Krzysztof Kosiński2450c552022-11-04 21:35:51 +0000264 'guava'
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000265 }
266 },
267 'androidx.room:room-migration': {
268 'host_and_device': True
269 },
270 'androidx.room:room-runtime': {},
271 'androidx.room:room-testing': {},
272 'androidx.room:room-compiler-processing': {
273 'host': True
274 },
275 'androidx.work:work-runtime': {},
276 'androidx.work:work-runtime-ktx': {},
277 'androidx.work:work-testing': {},
Allenab72f012018-01-29 18:10:23 -0800278
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400279 # Third-party dependencies
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000280 'com.google.android:flexbox': {
281 'name': 'flexbox',
282 'path': 'flexbox'
283 },
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400284
Jeff Gastonfa7c7e82018-04-06 13:35:48 -0400285 # Androidx Material Design Components
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000286 'com.google.android.material:material': {},
Alan Viverette95f6d362017-04-06 09:40:50 -0400287}
288
Alan Viverettecdfc9892021-08-31 19:35:58 +0000289# Mapping of POM dependencies to Soong build targets
290deps_rewrite = {
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000291 'auto-common': 'auto_common',
292 'auto-value-annotations': 'auto_value_annotations',
293 'com.google.auto.value:auto-value': 'libauto_value_plugin',
294 'monitor': 'androidx.test.monitor',
295 'rules': 'androidx.test.rules',
296 'runner': 'androidx.test.runner',
297 'androidx.test:core': 'androidx.test.core',
298 'com.squareup:javapoet': 'javapoet',
299 'com.google.guava:listenablefuture': 'guava-listenablefuture-prebuilt-jar',
300 'sqlite-jdbc': 'xerial-sqlite-jdbc',
301 'com.intellij:annotations': 'jetbrains-annotations',
302 'javax.annotation:javax.annotation-api': 'javax-annotation-api-prebuilt-host-jar',
303 'org.robolectric:robolectric': 'Robolectric_all-target',
304 'org.jetbrains.kotlin:kotlin-stdlib-common': 'kotlin-stdlib',
305 'org.jetbrains.kotlinx:kotlinx-coroutines-core': 'kotlinx_coroutines',
306 'org.jetbrains.kotlinx:kotlinx-coroutines-android': 'kotlinx_coroutines_android',
Jordan Demeulenaere606dca92022-07-29 16:09:28 +0200307 'org.jetbrains.kotlinx:kotlinx-coroutines-test':'kotlinx_coroutines_test',
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000308 'org.jetbrains.kotlinx:kotlinx-metadata-jvm': 'kotlinx_metadata_jvm',
Jordan Demeulenaere606dca92022-07-29 16:09:28 +0200309 'androidx.test.espresso:espresso-core':'androidx.test.espresso.core',
310 'androidx.test.espresso:espresso-idling-resource':'androidx.test.espresso.idling-resource',
Alan Viverettecdfc9892021-08-31 19:35:58 +0000311}
312
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000313# List of artifacts that will be updated from GMaven
314# Use pattern: `group:library:version:extension`
315# e.g.:
316# androidx.appcompat:appcompat:1.2.0:aar
317# Use `latest` to always fetch the latest version.
318# e.g.:
319# androidx.appcompat:appcompat:latest:aar
320# Also make sure you add `group:library`:{} to maven_to_make as well.
321gmaven_artifacts = {}
Alan Viverettef3c12722021-08-30 19:50:33 +0000322
Alan Viverette95f6d362017-04-06 09:40:50 -0400323# Always remove these files.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000324denylist_files = [
Alan Viverette95f6d362017-04-06 09:40:50 -0400325 'annotations.zip',
326 'public.txt',
327 'R.txt',
Alan Viverette44ad4e42017-08-09 17:45:00 -0400328 'AndroidManifest.xml',
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000329 os.path.join('libs', 'noto-emoji-compat-java.jar')
Alan Viverette95f6d362017-04-06 09:40:50 -0400330]
331
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000332artifact_pattern = re.compile(r'^(.+?)-(\d+\.\d+\.\d+(?:-\w+\d+)?(?:-[\d.]+)*)\.(jar|aar)$')
Alan Viverette95f6d362017-04-06 09:40:50 -0400333
Alan Viverettec960cfb2017-12-04 13:09:22 -0500334
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000335def name_for_artifact(group_artifact):
336 """Returns the build system target name for a given library's Maven coordinate.
337
338 Args:
339 group_artifact: an unversioned Maven artifact coordinate, ex. androidx.core:core
340 Returns:
341 The build system target name for the artifact, ex. androidx.core_core.
342 """
343 return group_artifact.replace(':', '_')
Alan Viverettec960cfb2017-12-04 13:09:22 -0500344
345
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000346def path_for_artifact(group_artifact):
347 """Returns the file system path for a given library's Maven coordinate.
348
349 Args:
350 group_artifact: an unversioned Maven artifact coordinate, ex. androidx.core:core
351 Returns:
352 The file system path for the artifact, ex. androidx/core/core.
353 """
354 return group_artifact.replace('.', '/').replace(':', '/')
Alan Viverettef5cb0e62017-11-17 15:15:23 -0500355
Alan Viverette95f6d362017-04-06 09:40:50 -0400356
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000357def populate_maven_to_make(mapping):
358 """Modifies the input mapping by expanding Maven coordinate keys into build target names and
359 paths.
Alan Viverette95f6d362017-04-06 09:40:50 -0400360
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000361 Args:
362 mapping: a map where the keys are Maven coordinates
363 """
364 for key in mapping:
365 if 'name' not in mapping[key]:
366 mapping[key]['name'] = name_for_artifact(key)
367 if 'path' not in maven_to_make[key]:
368 mapping[key]['path'] = path_for_artifact(key)
Alan Viverette45837092017-05-12 14:50:53 -0400369
370
Jeff Gastonc302bb92018-03-23 13:53:48 -0400371def detect_artifacts(maven_repo_dirs):
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000372 """Parses Maven libraries from the specified directories.
373
374 Args:
375 maven_repo_dirs: a list of maven repository roots
376 Returns:
377 A map of Maven coordinate keys to MavenLibraryInfo objects parsed from POM files.
378 """
Alan Viveretted4527e62017-05-11 15:03:25 -0400379 maven_lib_info = {}
380
Dan Willemsen814152e2017-11-06 13:22:11 -0800381 # Find the latest revision for each artifact, remove others
Jeff Gastonc302bb92018-03-23 13:53:48 -0400382 for repo_dir in maven_repo_dirs:
Dan Willemsen814152e2017-11-06 13:22:11 -0800383 for root, dirs, files in os.walk(repo_dir):
384 for file in files:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000385 if file[-4:] == '.pom':
Alan Viverettec960cfb2017-12-04 13:09:22 -0500386 # Read the POM (hack hack hack).
387 group_id = ''
388 artifact_id = ''
389 version = ''
390 file = os.path.join(root, file)
391 with open(file) as pom_file:
392 for line in pom_file:
393 if line[:11] == ' <groupId>':
394 group_id = line[11:-11]
395 elif line[:14] == ' <artifactId>':
396 artifact_id = line[14:-14]
397 elif line[:11] == ' <version>':
398 version = line[11:-11]
399 if group_id == '' or artifact_id == '' or version == '':
400 print_e('Failed to find Maven artifact data in ' + file)
401 continue
Alan Viverette95f6d362017-04-06 09:40:50 -0400402
Alan Viverettec960cfb2017-12-04 13:09:22 -0500403 # Locate the artifact.
404 artifact_file = file[:-4]
405 if os.path.exists(artifact_file + '.jar'):
406 artifact_file = artifact_file + '.jar'
407 elif os.path.exists(artifact_file + '.aar'):
408 artifact_file = artifact_file + '.aar'
409 else:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000410 # This error only occurs for a handful of gradle.plugin artifacts that only
411 # ship POM files, so we probably don't need to log unless we're debugging.
412 # print_e('Failed to find artifact for ' + artifact_file)
Alan Viverettec960cfb2017-12-04 13:09:22 -0500413 continue
414
415 # Make relative to root.
416 artifact_file = artifact_file[len(root) + 1:]
417
418 # Find the mapping.
419 group_artifact = group_id + ':' + artifact_id
Jeff Gaston3e622ba2018-03-26 23:24:46 -0400420 if group_artifact in maven_to_make:
Alan Viverettec960cfb2017-12-04 13:09:22 -0500421 key = group_artifact
Jeff Gaston3e622ba2018-03-26 23:24:46 -0400422 elif artifact_id in maven_to_make:
423 key = artifact_id
Alan Viverettec960cfb2017-12-04 13:09:22 -0500424 else:
Alan Viverettecdfc9892021-08-31 19:35:58 +0000425 # No mapping entry, skip this library.
Alan Viverettec960cfb2017-12-04 13:09:22 -0500426 continue
427
428 # Store the latest version.
429 version = LooseVersion(version)
430 if key not in maven_lib_info \
431 or version > maven_lib_info[key].version:
432 maven_lib_info[key] = MavenLibraryInfo(key, group_id, artifact_id, version,
433 root, repo_dir, artifact_file)
Alan Viverette95f6d362017-04-06 09:40:50 -0400434
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400435 return maven_lib_info
436
437
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000438def transform_maven_repos(maven_repo_dirs, transformed_dir, extract_res=True,
439 include_static_deps=True, include=None, exclude=None, prepend=None):
440 """Transforms a standard Maven repository to be compatible with the Android build system.
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400441
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000442 When using the include argument by itself, all other libraries will be excluded. When using the
443 exclude argument by itself, all other libraries will be included. When using both arguments, the
444 inclusion list will be applied followed by the exclusion list.
445
446 Args:
447 maven_repo_dirs: path to local Maven repository
448 transformed_dir: relative path for output, ex. androidx
449 extract_res: whether to extract Android resources like AndroidManifest.xml from AARs
450 include_static_deps: whether to pass --static-deps to pom2bp
451 include: list of Maven groupIds or unversioned artifact coordinates to include for
452 updates, ex. androidx.core or androidx.core:core
453 exclude: list of Maven groupIds or unversioned artifact coordinates to exclude from
454 updates, ex. androidx.core or androidx.core:core
455 prepend: Path to a file containing text to be inserted at the beginning of the generated
456 build file
457 Returns:
458 True if successful, false otherwise.
459 """
460 if exclude is None:
461 exclude = []
462 if include is None:
463 include = []
464
465 cwd = os.getcwd()
466 local_repo = os.path.join(cwd, transformed_dir)
Jeff Gastona68a8d42018-03-23 14:00:13 -0400467 working_dir = temp_dir
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400468
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000469 # Handle inclusions by stashing the remote artifacts for the inclusions, replacing the entire
470 # remote repo with the local repo, then restoring the stashed artifacts.
471 for remote_repo in maven_repo_dirs:
472 remote_repo = os.path.join(cwd, remote_repo)
473 paths_to_copy = []
474 for group_artifact in include:
475 artifact_path = os.path.join('m2repository', path_for_artifact(group_artifact))
476 remote_path = os.path.join(remote_repo, artifact_path)
477 working_path = os.path.join(working_dir, artifact_path)
478 if os.path.exists(remote_path):
479 print(f'Included {group_artifact} in update')
480 paths_to_copy.append([remote_path, working_path])
481
482 # Move included artifacts from repo to temp.
483 for [remote_path, working_path] in paths_to_copy:
484 mv(remote_path, working_path)
485
486 # Replace all remaining artifacts in remote repo with local repo.
487 cp(local_repo, remote_repo)
488
489 # Restore included artifacts to remote repo.
490 for [remote_path, working_path] in paths_to_copy:
491 mv(working_path, remote_path)
492
493 # Handle exclusions by replacing the remote artifacts for the exclusions with local artifacts.
494 # This must happen before we parse the artifacts.
495 for remote_repo in maven_repo_dirs:
496 for group_artifact in exclude:
497 artifact_path = os.path.join('m2repository', path_for_artifact(group_artifact))
498 remote_path = os.path.join(remote_repo, artifact_path)
499 if os.path.exists(remote_path):
500 rm(remote_path)
501 local_path = os.path.join(local_repo, artifact_path)
502 if os.path.exists(local_path):
503 print(f'Excluded {group_artifact} from update, used local artifact')
504 mv(local_path, remote_path)
505 else:
506 print(f'Excluded {group_artifact} from update, no local artifact present')
507
508 # Parse artifacts.
509 maven_lib_info = detect_artifacts(maven_repo_dirs)
510
Alan Viverettec960cfb2017-12-04 13:09:22 -0500511 if not maven_lib_info:
512 print_e('Failed to detect artifacts')
513 return False
514
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000515 # Move libraries into the working directory, performing any necessary transformations.
Alan Viveretted4527e62017-05-11 15:03:25 -0400516 for info in maven_lib_info.values():
Alan Viveretted8ce7222017-12-11 17:24:43 -0500517 transform_maven_lib(working_dir, info, extract_res)
Dan Willemsen814152e2017-11-06 13:22:11 -0800518
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000519 # Generate a single Android.bp that specifies to use all of the above artifacts.
Colin Cross74683bc2018-04-11 17:36:18 -0700520 makefile = os.path.join(working_dir, 'Android.bp')
Alan Viverette4ec9a172018-02-20 16:19:31 -0500521 with open(makefile, 'w') as f:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000522 args = ['pom2bp']
523 args.extend(['-sdk-version', '31'])
524 args.extend(['-default-min-sdk-version', '24'])
Jeff Gaston1cc06092018-03-28 15:51:02 -0400525 if include_static_deps:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000526 args.append('-static-deps')
527 if prepend:
528 args.append(f'-prepend={prepend}')
529 rewrite_names = sorted(maven_to_make.keys())
530 args.extend([f'-rewrite=^{name}$={maven_to_make[name]["name"]}' for name in rewrite_names])
531 args.extend([f'-rewrite=^{key}$={value}' for key, value in deps_rewrite.items()])
532 args.extend(["-extra-static-libs=" + maven_to_make[name]['name'] + "=" + ",".join(
533 sorted(maven_to_make[name]['extra-static-libs'])) for name in maven_to_make if
534 'extra-static-libs' in maven_to_make[name]])
535 args.extend(["-optional-uses-libs=" + maven_to_make[name]['name'] + "=" + ",".join(
536 sorted(maven_to_make[name]['optional-uses-libs'])) for name in maven_to_make if
537 'optional-uses-libs' in maven_to_make[name]])
538 args.extend([f'-host={name}' for name in maven_to_make
539 if maven_to_make[name].get('host')])
540 args.extend([f'-host-and-device={name}' for name in maven_to_make
541 if maven_to_make[name].get('host_and_device')])
542 args.extend(['.'])
Dan Willemsen814152e2017-11-06 13:22:11 -0800543 subprocess.check_call(args, stdout=f, cwd=working_dir)
Alan Viverette95f6d362017-04-06 09:40:50 -0400544
545 # Replace the old directory.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000546 local_repo = os.path.join(cwd, transformed_dir)
547 mv(working_dir, local_repo)
Alan Viverettec960cfb2017-12-04 13:09:22 -0500548 return True
Alan Viverette95f6d362017-04-06 09:40:50 -0400549
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000550
Alan Viveretted8ce7222017-12-11 17:24:43 -0500551def transform_maven_lib(working_dir, artifact_info, extract_res):
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000552 """Transforms the specified artifact for use in the Android build system.
553
554 Moves relevant files for the artifact represented by artifact_info of type MavenLibraryInfo into
555 the appropriate path inside working_dir, unpacking files needed by the build system from AARs.
556
557 Args:
558 working_dir: The directory into which the artifact should be moved
559 artifact_info: A MavenLibraryInfo representing the library artifact
560 extract_res: True to extract resources from AARs, false otherwise.
561 """
Dan Willemsen814152e2017-11-06 13:22:11 -0800562 # Move library into working dir
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000563 new_dir = os.path.normpath(
564 os.path.join(working_dir, os.path.relpath(artifact_info.dir, artifact_info.repo_dir)))
Jeff Gastonc302bb92018-03-23 13:53:48 -0400565 mv(artifact_info.dir, new_dir)
Dan Willemsen814152e2017-11-06 13:22:11 -0800566
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000567 maven_lib_type = os.path.splitext(artifact_info.file)[1][1:]
Alan Viveretted4527e62017-05-11 15:03:25 -0400568
Alan Viverettef3c12722021-08-30 19:50:33 +0000569 group_artifact = artifact_info.key
570 make_lib_name = maven_to_make[group_artifact]['name']
571 make_dir_name = maven_to_make[group_artifact]['path']
Alan Viveretted4527e62017-05-11 15:03:25 -0400572
Alan Viverette129555e2018-01-30 09:57:57 -0500573 artifact_file = os.path.join(new_dir, artifact_info.file)
574
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000575 if maven_lib_type == 'aar':
Colin Cross59b59db2018-04-24 13:58:05 -0700576 if extract_res:
577 target_dir = os.path.join(working_dir, make_dir_name)
578 if not os.path.exists(target_dir):
579 os.makedirs(target_dir)
Dan Willemsen814152e2017-11-06 13:22:11 -0800580
Alan Viverettec960cfb2017-12-04 13:09:22 -0500581 process_aar(artifact_file, target_dir)
Alan Viveretted4527e62017-05-11 15:03:25 -0400582
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000583 with zipfile.ZipFile(artifact_file) as zip_file:
584 manifests_dir = os.path.join(working_dir, 'manifests')
585 zip_file.extract('AndroidManifest.xml', os.path.join(manifests_dir, make_lib_name))
Alan Viveretted4527e62017-05-11 15:03:25 -0400586
Alan Viverette95f6d362017-04-06 09:40:50 -0400587
Alan Viverettec960cfb2017-12-04 13:09:22 -0500588def process_aar(artifact_file, target_dir):
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000589 """Extracts and cleans up the contents of an AAR file to the specified directory.
590
591 Removes classes.jar, empty directories, and denylisted files.
592
593 Args:
594 artifact_file: path to the AAR to extract
595 target_dir: directory into which the contents should be extracted
596 """
Alan Viverette95f6d362017-04-06 09:40:50 -0400597 # Extract AAR file to target_dir.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000598 with zipfile.ZipFile(artifact_file) as zip_file:
599 zip_file.extractall(target_dir)
Alan Viverette95f6d362017-04-06 09:40:50 -0400600
Dan Willemsen814152e2017-11-06 13:22:11 -0800601 # Remove classes.jar
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000602 classes_jar = os.path.join(target_dir, 'classes.jar')
Alan Viverette95f6d362017-04-06 09:40:50 -0400603 if os.path.exists(classes_jar):
Dan Willemsen814152e2017-11-06 13:22:11 -0800604 os.remove(classes_jar)
Alan Viverette95f6d362017-04-06 09:40:50 -0400605
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000606 # Remove empty dirs.
607 for root, dirs, files in os.walk(target_dir, topdown=False):
608 for dir_name in dirs:
609 dir_path = os.path.join(root, dir_name)
Alan Viverette95f6d362017-04-06 09:40:50 -0400610 if not os.listdir(dir_path):
611 os.rmdir(dir_path)
612
613 # Remove top-level cruft.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000614 for file in denylist_files:
Alan Viverette95f6d362017-04-06 09:40:50 -0400615 file_path = os.path.join(target_dir, file)
616 if os.path.exists(file_path):
617 os.remove(file_path)
618
Alan Viverettef17c9402017-07-19 12:57:40 -0400619
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000620def fetch_gmaven_artifact(artifact):
621 """Fetch a GMaven artifact.
622
623 Downloads a GMaven artifact
624 (https://developer.android.com/studio/build/dependencies#gmaven-access)
625
626 Args:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000627 artifact: an instance of GMavenArtifact.
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000628 """
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000629 pom_path = maven_path_for_artifact(
630 'gmaven', artifact.group, artifact.library, artifact.version, 'pom')
631 artifact_path = maven_path_for_artifact(
632 'gmaven', artifact.group, artifact.library, artifact.version, artifact.ext)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000633
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000634 download_file_to_disk(artifact.get_pom_file_url(), pom_path)
635 download_file_to_disk(artifact.get_artifact_url(), artifact_path)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000636
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000637 return os.path.dirname(artifact_path)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000638
639
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000640def download_file_to_disk(url, filepath):
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000641 """Download the file at URL to the location dictated by the path.
642
643 Args:
644 url: Remote URL to download file from.
645 filepath: Filesystem path to write the file to.
646 """
647 print(f'Downloading URL: {url}')
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000648 file_data = request.urlopen(url)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000649
650 try:
651 os.makedirs(os.path.dirname(filepath))
652 except os.error:
653 # This is a common situation - os.makedirs fails if dir already exists.
654 pass
655 try:
656 with open(filepath, 'wb') as f:
657 f.write(six.ensure_binary(file_data.read()))
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000658 except Exception as e:
659 print_e(e.__class__, 'occurred while reading', filepath)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000660 os.remove(os.path.dirname(filepath))
661 raise
662
663
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000664def update_gmaven(gmaven_artifacts_list):
665 artifacts = [GMavenArtifact(artifact) for artifact in gmaven_artifacts_list]
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000666 for artifact in artifacts:
667 if artifact.version == 'latest':
668 artifact.version = artifact.get_latest_version()
669
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000670 if not transform_maven_repos(['gmaven'], gmaven_dir, extract_res=False):
671 return []
672 return [artifact.key for artifact in artifacts]
673
674
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000675def update_androidx(target, build_id, local_file, include, exclude, beyond_corp):
676 """Fetches and extracts Jetpack library prebuilts.
677
678 Args:
679 target: Android build server target name, must be specified if local_file is empty
680 build_id: Optional Android build server ID, must be specified if local_file is empty
681 local_file: Optional local top-of-tree ZIP, must be specified if build_id is empty
682 include: List of Maven groupIds or unversioned artifact coordinates to include for
683 updates, ex. android.core or androidx.core:core
684 exclude: List of Maven groupIds or unversioned artifact coordinates to exclude from
685 updates, ex. android.core or androidx.core:core
686 beyond_corp: Whether to use BeyondCorp-compatible artifact fetcher
687 Returns:
688 True if successful, false otherwise.
689 """
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400690 if build_id:
Anthony Chenacbb4872018-07-02 11:22:48 -0700691 repo_file = 'top-of-tree-m2repository-all-%s.zip' % build_id.fs_id
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000692 repo_dir = fetch_and_extract(target, build_id.url_id, repo_file, beyond_corp, None)
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400693 else:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000694 repo_dir = fetch_and_extract(target, None, None, beyond_corp, local_file)
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400695 if not repo_dir:
696 print_e('Failed to extract AndroidX repository')
697 return False
698
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000699 prepend_path = os.path.relpath('update_prebuilts/prepend_androidx_license', start=temp_dir)
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400700
Tony Mak0f658752019-07-19 11:11:05 +0100701 # Transform the repo archive into a Makefile-compatible format.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000702 if not transform_maven_repos([repo_dir], androidx_dir, extract_res=False, include=include,
703 exclude=exclude, prepend=prepend_path):
Tony Mak0f658752019-07-19 11:11:05 +0100704 return False
705
706 # Import JavaPlugins.bp in Android.bp.
707 makefile = os.path.join(androidx_dir, 'Android.bp')
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000708 with open(makefile, 'a+') as f:
Tony Mak0f658752019-07-19 11:11:05 +0100709 f.write('\nbuild = ["JavaPlugins.bp"]\n')
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000710
711 # Keep OWNERs file, JavaPlugins.bp file, and TEST_MAPPING files untouched.
Nick Anthonybac2fca2022-11-03 18:56:57 +0000712 files_to_restore = [androidx_owners, java_plugins_bp_path, test_mapping_file,
713 compose_test_mapping_file]
714 for file_to_restore in files_to_restore:
715 # Ignore any output or error - these files are not gauranteed to exist, but
716 # if they do, we want to restore them.
717 subprocess.call(['git', 'restore', file_to_restore],
718 stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
Tony Mak0f658752019-07-19 11:11:05 +0100719
720 return True
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400721
Alan Viverette6dc45752020-04-16 14:56:20 +0000722
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000723def update_jetifier(target, build_id, beyond_corp):
724 """
725 Fetches and extracts Jetifier tool prebuilts.
726
727 Args:
728 target: Android build server target name
729 build_id: Android build server ID
730 beyond_corp: Whether to use BeyondCorp-compatible artifact fetcher
731 Return:
732 Whether the prebuilt was successfully updated.
733 """
Jeff Gaston782c3e32018-02-06 14:36:17 -0500734 repo_file = 'jetifier-standalone.zip'
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000735 repo_dir = fetch_and_extract(target, build_id.url_id, repo_file, beyond_corp)
Jeff Gaston782c3e32018-02-06 14:36:17 -0500736 if not repo_dir:
737 print_e('Failed to extract Jetifier')
738 return False
739
740 rm(jetifier_dir)
Jeff Gaston553a4372018-03-29 18:34:22 -0400741 mv(os.path.join(repo_dir, 'jetifier-standalone'), jetifier_dir)
742 os.chmod(os.path.join(jetifier_dir, 'bin', 'jetifier-standalone'), 0o755)
Jeff Gaston782c3e32018-02-06 14:36:17 -0500743 return True
744
Alan Viverette7e897e22018-03-09 15:24:10 -0500745
Alan Viverette6dc45752020-04-16 14:56:20 +0000746def update_constraint(local_file):
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000747 """
748 Extracts ConstraintLayout library prebuilts.
749
750 Args:
751 local_file: local Maven repository ZIP containing library artifacts
752 Return:
753 Whether the prebuilts were successfully updated.
754 """
Jeff Gaston9edf86c2018-04-18 13:45:23 -0400755 repo_dir = extract_artifact(local_file)
756 if not repo_dir:
Alan Viverette6dc45752020-04-16 14:56:20 +0000757 print_e('Failed to extract Constraint Layout')
Jeff Gaston9edf86c2018-04-18 13:45:23 -0400758 return False
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000759 return transform_maven_repos([repo_dir], os.path.join(extras_dir, 'constraint-layout-x'),
760 extract_res=False)
Jeff Gaston9edf86c2018-04-18 13:45:23 -0400761
Alan Viverette45837092017-05-12 14:50:53 -0400762
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000763def update_material(local_file):
764 """
765 Extracts Material Design Components library prebuilts.
766
767 Args:
768 local_file: local Maven repository ZIP containing library artifacts
769 Return:
770 Whether the prebuilts were successfully updated.
771 """
772 design_dir = extract_artifact(local_file)
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400773 if not design_dir:
Alan Viverette6dc45752020-04-16 14:56:20 +0000774 print_e('Failed to extract Material Design Components')
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400775 return False
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000776 return transform_maven_repos([design_dir], os.path.join(extras_dir, 'material-design-x'),
777 extract_res=False)
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400778
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400779
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000780def update_framework(target, build_id, sdk_dir, beyond_corp):
Anton Hansson83f92172020-03-26 11:12:03 +0000781 api_scope_list = ['public', 'system', 'test', 'module-lib', 'system-server']
Sundong Ahn66091f22018-08-29 18:54:28 +0900782 if sdk_dir == 'current':
783 api_scope_list.append('core')
784
785 for api_scope in api_scope_list:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000786 target_dir = os.path.join(sdk_dir, api_scope)
Sundong Ahn66091f22018-08-29 18:54:28 +0900787 if api_scope == 'core':
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000788 artifact_to_path = {'core.current.stubs.jar': os.path.join(target_dir, 'android.jar')}
Sundong Ahn66091f22018-08-29 18:54:28 +0900789 else:
Paul Duffin6815a312021-10-28 13:02:51 +0100790 artifact_to_path = {
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000791 'apistubs/android/' + api_scope + '/*.jar': os.path.join(target_dir, '*'),
Paul Duffin6815a312021-10-28 13:02:51 +0100792 }
793 if api_scope == 'public' or api_scope == 'module-lib':
794 # Distinct core-for-system-modules.jar files are only provided
795 # for the public and module-lib API surfaces.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000796 artifact_to_path[
797 'system-modules/' + api_scope + '/core-for-system-modules.jar'] = os.path.join(
798 target_dir, '*')
Anton Hansson1d01a032018-04-09 10:29:37 +0100799
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000800 if not fetch_artifacts(target, build_id, artifact_to_path, beyond_corp):
Anton Hansson1d01a032018-04-09 10:29:37 +0100801 return False
802
Jiyong Park1d1c9632018-05-29 17:45:27 +0900803 if api_scope == 'public':
Anton Hansson1d01a032018-04-09 10:29:37 +0100804 # Fetch a few artifacts from the public sdk.
Sundong Ahn66091f22018-08-29 18:54:28 +0900805 artifact = 'sdk-repo-linux-platforms-%s.zip' % build_id.fs_id
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000806 artifact_path = fetch_artifact(target, build_id.url_id, artifact, beyond_corp)
Anton Hansson9709fd42018-04-03 16:52:13 +0100807 if not artifact_path:
808 return False
Anton Hansson1d01a032018-04-09 10:29:37 +0100809
810 with zipfile.ZipFile(artifact_path) as zipFile:
Colin Crossd338d702020-07-10 19:17:54 -0700811 extra_files = [
812 'android.jar',
813 'framework.aidl',
814 'uiautomator.jar',
Colin Crossd338d702020-07-10 19:17:54 -0700815 'data/annotations.zip',
816 'data/api-versions.xml']
817 for filename in extra_files:
Anton Hanssona26e4812020-03-25 12:54:39 +0000818 matches = list(filter(lambda path: filename in path, zipFile.namelist()))
819 if len(matches) != 1:
820 print_e('Expected 1 file named \'%s\' in zip %s, found %d' %
821 (filename, zipFile.filename, len(matches)))
822 return False
823 zip_path = matches[0]
824 src_path = zipFile.extract(zip_path)
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000825 dst_path = os.path.join(target_dir, filename)
Anton Hanssona26e4812020-03-25 12:54:39 +0000826 mv(src_path, dst_path)
Anton Hansson9709fd42018-04-03 16:52:13 +0100827
Anton Hansson73be1512021-06-24 10:56:05 +0100828 # Filtered API DB is currently only available for "public"
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000829 fetch_artifacts(target, build_id, {'api-versions-public-filtered.xml': os.path.join(
830 target_dir, 'data/api-versions-filtered.xml')}, beyond_corp)
Anton Hansson73be1512021-06-24 10:56:05 +0100831
Alan Viverettecd3de262017-08-14 09:51:30 -0400832 return True
Alan Viverette45837092017-05-12 14:50:53 -0400833
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000834
Sundong Ahncc34cc32018-07-11 15:18:47 +0900835def update_makefile(build_id):
836 template = '"%s",\n\
837 "current"'
838 makefile = os.path.join(git_dir, 'Android.bp')
839
840 with open(makefile, 'r+') as f:
841 contents = f.read().replace('"current"', template % build_id)
842 f.seek(0)
843 f.write(contents)
844
845 return True
Alan Viverette45837092017-05-12 14:50:53 -0400846
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000847
848def finalize_sdk(target, build_id, sdk_version, beyond_corp):
Anton Hansson1d01a032018-04-09 10:29:37 +0100849 target_finalize_dir = '%d' % sdk_version
Anton Hansson9709fd42018-04-03 16:52:13 +0100850
Anton Hanssonaa554c02020-04-30 14:06:20 +0100851 for api_scope in ['public', 'system', 'test', 'module-lib', 'system-server']:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000852 artifact_to_path = {f'apistubs/android/{api_scope}/api/*.txt': os.path.join(
853 target_finalize_dir, api_scope, 'api', '*')}
Sundong Ahn66091f22018-08-29 18:54:28 +0900854
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000855 if not fetch_artifacts(target, build_id, artifact_to_path, beyond_corp):
Sundong Ahn66091f22018-08-29 18:54:28 +0900856 return False
857
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000858 return update_framework(target, build_id, target_finalize_dir, beyond_corp) and update_makefile(
859 target_finalize_dir)
Anton Hansson9709fd42018-04-03 16:52:13 +0100860
Anton Hansson9709fd42018-04-03 16:52:13 +0100861
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000862def update_framework_current(target, build_id, beyond_corp):
863 return update_framework(target, build_id, current_path, beyond_corp)
Anton Hansson9709fd42018-04-03 16:52:13 +0100864
865
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000866def update_buildtools(target, arch, build_id, beyond_corp):
Jeff Gaston13e38412018-02-06 14:45:36 -0500867 artifact_path = fetch_and_extract(target, build_id.url_id,
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000868 f'sdk-repo-{arch}-build-tools-{build_id.fs_id}.zip',
869 beyond_corp)
Alan Viverettec1c32b62017-12-20 09:40:36 -0500870 if not artifact_path:
871 return False
872
873 top_level_dir = os.listdir(artifact_path)[0]
874 src_path = os.path.join(artifact_path, top_level_dir)
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000875 dst_path = os.path.join(buildtools_dir, arch)
Colin Cross20648d32021-02-12 13:30:51 -0800876
877 # There are a few libraries that have been manually added to the
878 # build tools, copy them from the destination back to the source
879 # before the destination is overwritten.
880 files_to_save = (
881 'lib64/libconscrypt_openjdk_jni.dylib',
882 'lib64/libconscrypt_openjdk_jni.so',
883 'bin/lib64/libwinpthread-1.dll',
884 )
885 for file in files_to_save:
886 src_file = os.path.join(dst_path, file)
887 dst_file = os.path.join(src_path, file)
888 if os.path.exists(dst_path):
889 mv(src_file, dst_file)
890
Alan Viverettec1c32b62017-12-20 09:40:36 -0500891 mv(src_path, dst_path)
892
893 # Move all top-level files to /bin and make them executable
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000894 bin_path = os.path.join(dst_path, 'bin')
895 top_level_files = filter(lambda e: os.path.isfile(os.path.join(dst_path, e)), os.listdir(dst_path))
Alan Viverettec1c32b62017-12-20 09:40:36 -0500896 for file in top_level_files:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000897 src_file = os.path.join(dst_path, file)
898 dst_file = os.path.join(bin_path, file)
Alan Viverettec1c32b62017-12-20 09:40:36 -0500899 mv(src_file, dst_file)
900 os.chmod(dst_file, 0o755)
901
Colin Cross6673ceb2021-02-12 13:14:14 -0800902 # Make the files under lld-bin executable
903 lld_bin_files = os.listdir(os.path.join(dst_path, 'lld-bin'))
904 for file in lld_bin_files:
905 os.chmod(os.path.join(dst_path, 'lld-bin', file), 0o755)
906
Alan Viverettec1c32b62017-12-20 09:40:36 -0500907 # Remove renderscript
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000908 rm(os.path.join(dst_path, 'renderscript'))
Alan Viverettec1c32b62017-12-20 09:40:36 -0500909
910 return True
911
912
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000913def has_uncommitted_changes():
Jeff Gastoncc296a82018-03-23 14:33:24 -0400914 try:
915 # Make sure we don't overwrite any pending changes.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000916 diff_command = f'cd {git_dir} && git diff --quiet'
917 subprocess.check_call(diff_command, shell=True)
918 subprocess.check_call(f'{diff_command} --cached', shell=True)
Jeff Gastoncc296a82018-03-23 14:33:24 -0400919 return False
920 except subprocess.CalledProcessError:
921 return True
922
923
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000924def main():
925 parser = argparse.ArgumentParser(
926 description='Update current prebuilts')
927 parser.add_argument(
928 'source', nargs='?',
929 help='Build server build ID or local Maven ZIP file')
930 parser.add_argument(
931 '-m', '--material', action='store_true',
932 help='If specified, updates only Material Design Components')
933 parser.add_argument(
934 '-c', '--constraint', action='store_true',
935 help='If specified, updates only Constraint Layout')
936 parser.add_argument(
937 '-j', '--jetifier', action='store_true',
938 help='If specified, updates only Jetifier')
939 parser.add_argument(
940 '-p', '--platform', action='store_true',
941 help='If specified, updates only the Android Platform')
942 parser.add_argument(
943 '-f', '--finalize_sdk', type=int,
944 help='Finalize the build as the specified SDK version. Must be used together with -e')
945 parser.add_argument(
946 '-e', '--finalize_extension', type=int,
947 help='Finalize the build as the specified extension SDK version. Must be used together with -f')
948 parser.add_argument('--bug', type=int, help='The bug number to add to the commit message.')
949 parser.add_argument(
950 '--sdk_target',
951 default=framework_sdk_target,
952 help='If specified, the name of the build target from which to retrieve the SDK when -p or -f '
953 'is specified.')
954 parser.add_argument(
955 '-b', '--buildtools', action='store_true',
956 help='If specified, updates only the Build Tools')
957 parser.add_argument(
958 '-x', '--androidx', action='store_true',
959 help='If specified, updates only the Jetpack (androidx) libraries excluding those covered by '
960 'other arguments')
961 parser.add_argument(
962 '--include', action='append', default=[],
963 help='If specified with -x, includes the specified Jetpack library Maven group or artifact for '
964 'updates. Applied before exclude.')
965 parser.add_argument(
966 '--exclude', action='append', default=[],
967 help='If specified with -x, excludes the specified Jetpack library Maven group or artifact '
968 'from updates')
969 parser.add_argument(
970 '-g', '--gmaven', action='store_true',
971 help='If specified, updates only the artifact from GMaven libraries excluding those covered by '
972 'other arguments')
973 parser.add_argument(
974 '--commit-first', action='store_true',
975 help='If specified, then if uncommited changes exist, commit before continuing')
976 parser.add_argument(
977 '--beyond-corp', action='store_true',
978 help='If specified, then fetch artifacts with tooling that works on BeyondCorp devices')
Anton Hansson4bcebac2022-04-07 17:23:18 +0100979
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000980 rm(temp_dir)
Alan Viveretted4527e62017-05-11 15:03:25 -0400981
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000982 args = parser.parse_args()
Jeff Gastoncc296a82018-03-23 14:33:24 -0400983
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000984 # Validate combinations of arguments.
985 if not args.source and (args.platform or args.buildtools or args.jetifier
986 or args.androidx or args.material or args.finalize_sdk
987 or args.constraint):
988 parser.error('You must specify a build ID or local Maven ZIP file')
989 sys.exit(1)
990 if not (args.gmaven or args.platform or args.buildtools or args.jetifier
991 or args.androidx or args.material or args.finalize_sdk
992 or args.finalize_extension or args.constraint):
993 parser.error('You must specify at least one target to update')
994 sys.exit(1)
995 if (args.finalize_sdk is None) != (args.finalize_extension is None):
996 parser.error('Either both or neither of -e and -f must be specified.')
997 sys.exit(1)
998 if args.finalize_sdk and not args.bug:
999 parser.error('Specifying a bug ID with --bug is required when finalizing an SDK.')
1000 sys.exit(1)
Alan Viveretted4527e62017-05-11 15:03:25 -04001001
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001002 # Validate the build environment for POM-dependent targets.
1003 if (args.constraint or args.material or args.androidx or args.gmaven) \
1004 and which('pom2bp') is None:
1005 parser.error('Cannot find pom2bp in path; please run lunch to set up build environment. '
1006 'You may also need to run \'m pom2bp\' if it hasn\'t been built already.')
1007 sys.exit(1)
Anton Hansson57a1b142022-04-07 17:27:41 +01001008
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001009 # Validate the git status.
1010 if has_uncommitted_changes():
1011 if args.commit_first:
1012 subprocess.check_call(f'cd {git_dir} && git add -u', shell=True)
1013 subprocess.check_call(f'cd {git_dir} && git commit -m \'save working state\'',
1014 shell=True)
1015 if has_uncommitted_changes():
1016 self_file = os.path.basename(__file__)
1017 print_e(f'FAIL: There are uncommitted changes here. Please commit or stash before '
1018 f'continuing, because {self_file} will run "git reset --hard" if execution fails')
1019 sys.exit(1)
Anton Hansson4bcebac2022-04-07 17:23:18 +01001020
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001021 if args.bug:
1022 commit_msg_suffix = '\n\nBug: {args.bug}'
Alan Viverette129555e2018-01-30 09:57:57 -05001023 else:
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001024 commit_msg_suffix = ''
Alan Viveretted4527e62017-05-11 15:03:25 -04001025
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001026 # Are we fetching a build ID or using a local file?
1027 build_id = None
1028 file = None
1029 if args.source:
1030 build_id = parse_build_id(args.source)
1031 if build_id is None:
1032 file = args.source
1033
Alan Viveretted4527e62017-05-11 15:03:25 -04001034 try:
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001035 components = []
1036 if args.constraint:
1037 if update_constraint(file):
1038 components.append('Constraint Layout')
1039 else:
1040 print_e('Failed to update Constraint Layout, aborting...')
1041 sys.exit(1)
1042 if args.material:
1043 if update_material(file):
1044 components.append('Material Design Components')
1045 else:
1046 print_e('Failed to update Material Design Components, aborting...')
1047 sys.exit(1)
1048 if args.gmaven:
1049 updated_artifacts = update_gmaven(gmaven_artifacts)
1050 if updated_artifacts:
1051 components.append('\n'.join(updated_artifacts))
1052 else:
1053 print_e('Failed to update GMaven, aborting...')
1054 sys.exit(1)
1055 if args.androidx:
1056 if update_androidx('androidx', build_id, file, args.include, args.exclude,
1057 args.beyond_corp):
1058 components.append('AndroidX')
1059 else:
1060 print_e('Failed to update AndroidX, aborting...')
1061 sys.exit(1)
1062 if args.jetifier:
1063 if update_jetifier('androidx', build_id, args.beyond_corp):
1064 components.append('Jetifier')
1065 else:
1066 print_e('Failed to update Jetifier, aborting...')
1067 sys.exit(1)
1068 if args.platform or args.finalize_sdk:
1069 if update_framework_current(args.sdk_target, build_id, args.beyond_corp):
1070 components.append('platform SDK')
1071 else:
1072 print_e('Failed to update platform SDK, aborting...')
1073 sys.exit(1)
1074 if args.finalize_sdk:
1075 n = args.finalize_sdk
1076 if not finalize_sdk(args.sdk_target, build_id, n, args.beyond_corp):
1077 print_e('Failed to finalize SDK %d, aborting...' % n)
1078 sys.exit(1)
1079
1080 # We commit the finalized dir separately from the current sdk update.
1081 msg = f'Import final sdk version {n} from build {build_id.url_id}{commit_msg_suffix}'
1082 subprocess.check_call(['git', 'add', '%d' % n])
1083 subprocess.check_call(['git', 'add', 'Android.bp'])
1084 subprocess.check_call(['git', 'commit', '-m', msg])
1085
1086 # Finalize extension sdk level
1087 readme = (f'- {args.finalize_extension}: Finalized together with '
1088 'Android {args.finalize_sdk} (all modules)')
1089 cmd = extension_sdk_finalization_cmd.format(
1090 readme=readme,
1091 bug=args.bug,
1092 extension_version=args.finalize_extension,
1093 build_id=build_id.url_id)
1094 subprocess.check_call(shlex.split(cmd), cwd=repo_root_dir.resolve())
1095 if args.buildtools:
1096 if update_buildtools('sdk_mac', 'darwin', build_id, args.beyond_corp) \
1097 and update_buildtools('sdk', 'linux', build_id, args.beyond_corp) \
1098 and update_buildtools('sdk', 'windows', build_id, args.beyond_corp):
1099 components.append('build tools')
1100 else:
1101 print_e('Failed to update build tools, aborting...')
1102 sys.exit(1)
1103
1104 # Build the git commit.
1105 subprocess.check_call(['git', 'add', current_path, buildtools_dir])
1106
1107 # Build the commit message.
1108 components_msg = ', '.join(components)
1109 argv_msg = ' '.join(sys.argv)
1110 if not args.source and args.gmaven:
1111 src_msg = 'GMaven'
1112 elif not args.source.isnumeric():
1113 src_msg = 'local Maven ZIP'
1114 else:
1115 src_msg = f'build {build_id.url_id}'
1116 msg = f'Import {components_msg} from {src_msg}\n\n{argv_msg}{commit_msg_suffix}'
1117
1118 # Create the git commit.
1119 subprocess.check_call(['git', 'commit', '-q', '-m', msg])
1120
1121 if args.finalize_sdk:
1122 print('NOTE: Created three commits:')
1123 subprocess.check_call(['git', 'log', '-3', '--oneline'])
1124 else:
1125 print('Created commit:')
1126 subprocess.check_call(['git', 'log', '-1', '--oneline'])
1127 print('Remember to test this change before uploading it to Gerrit!')
1128
1129 finally:
1130 # Revert all stray files, including the downloaded zip.
1131 try:
1132 with open(os.devnull, 'w') as bitbucket:
1133 subprocess.check_call(['git', 'add', '-Af', '.'], stdout=bitbucket)
1134 subprocess.check_call(
1135 ['git', 'commit', '-m', 'COMMIT TO REVERT - RESET ME!!!', '--allow-empty'],
1136 stdout=bitbucket)
1137 subprocess.check_call(['git', 'reset', '--hard', 'HEAD~1'], stdout=bitbucket)
1138 except subprocess.CalledProcessError:
1139 print_e('ERROR: Failed cleaning up, manual cleanup required!!!')
1140
1141
1142# Add automatic entries to maven_to_make.
1143populate_maven_to_make(maven_to_make)
1144
1145if __name__ == '__main__':
1146 main()