blob: a1bba23398e1ac4a3c7ff3808f632205b584da87 [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 },
Anvesh Renikindi82b59882022-11-22 01:33:01 +0000235 'androidx.constraintlayout:constraintlayout-core': {},
236 'androidx.constraintlayout:constraintlayout-compose': {},
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400237 # AndroidX for Architecture Components
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000238 'androidx.arch.core:core-common': {},
239 'androidx.arch.core:core-runtime': {},
240 'androidx.lifecycle:lifecycle-common': {},
241 'androidx.lifecycle:lifecycle-common-java8': {},
242 'androidx.lifecycle:lifecycle-extensions': {},
243 'androidx.lifecycle:lifecycle-livedata': {},
244 'androidx.lifecycle:lifecycle-livedata-ktx': {},
245 'androidx.lifecycle:lifecycle-livedata-core': {},
246 'androidx.lifecycle:lifecycle-livedata-core-ktx': {},
247 'androidx.lifecycle:lifecycle-process': {},
248 'androidx.lifecycle:lifecycle-runtime': {},
249 'androidx.lifecycle:lifecycle-runtime-ktx': {},
250 'androidx.lifecycle:lifecycle-service': {},
251 'androidx.lifecycle:lifecycle-viewmodel': {},
252 'androidx.lifecycle:lifecycle-viewmodel-ktx': {},
253 'androidx.lifecycle:lifecycle-viewmodel-savedstate': {},
254 'androidx.paging:paging-common': {},
255 'androidx.paging:paging-common-ktx': {},
256 'androidx.paging:paging-runtime': {},
257 'androidx.sqlite:sqlite': {},
258 'androidx.sqlite:sqlite-framework': {},
259 'androidx.room:room-common': {
260 'host_and_device': True
261 },
262 'androidx.room:room-compiler': {
263 'host': True,
264 'extra-static-libs': {
Krzysztof Kosiński2450c552022-11-04 21:35:51 +0000265 'guava'
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000266 }
267 },
268 'androidx.room:room-migration': {
269 'host_and_device': True
270 },
271 'androidx.room:room-runtime': {},
272 'androidx.room:room-testing': {},
273 'androidx.room:room-compiler-processing': {
274 'host': True
275 },
276 'androidx.work:work-runtime': {},
277 'androidx.work:work-runtime-ktx': {},
278 'androidx.work:work-testing': {},
Allenab72f012018-01-29 18:10:23 -0800279
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400280 # Third-party dependencies
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000281 'com.google.android:flexbox': {
282 'name': 'flexbox',
283 'path': 'flexbox'
284 },
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400285
Jeff Gastonfa7c7e82018-04-06 13:35:48 -0400286 # Androidx Material Design Components
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000287 'com.google.android.material:material': {},
Alan Viverette95f6d362017-04-06 09:40:50 -0400288}
289
Alan Viverettecdfc9892021-08-31 19:35:58 +0000290# Mapping of POM dependencies to Soong build targets
291deps_rewrite = {
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000292 'auto-common': 'auto_common',
293 'auto-value-annotations': 'auto_value_annotations',
294 'com.google.auto.value:auto-value': 'libauto_value_plugin',
295 'monitor': 'androidx.test.monitor',
296 'rules': 'androidx.test.rules',
297 'runner': 'androidx.test.runner',
298 'androidx.test:core': 'androidx.test.core',
299 'com.squareup:javapoet': 'javapoet',
300 'com.google.guava:listenablefuture': 'guava-listenablefuture-prebuilt-jar',
301 'sqlite-jdbc': 'xerial-sqlite-jdbc',
302 'com.intellij:annotations': 'jetbrains-annotations',
303 'javax.annotation:javax.annotation-api': 'javax-annotation-api-prebuilt-host-jar',
304 'org.robolectric:robolectric': 'Robolectric_all-target',
305 'org.jetbrains.kotlin:kotlin-stdlib-common': 'kotlin-stdlib',
306 'org.jetbrains.kotlinx:kotlinx-coroutines-core': 'kotlinx_coroutines',
307 'org.jetbrains.kotlinx:kotlinx-coroutines-android': 'kotlinx_coroutines_android',
Jordan Demeulenaere606dca92022-07-29 16:09:28 +0200308 'org.jetbrains.kotlinx:kotlinx-coroutines-test':'kotlinx_coroutines_test',
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000309 'org.jetbrains.kotlinx:kotlinx-metadata-jvm': 'kotlinx_metadata_jvm',
Jordan Demeulenaere606dca92022-07-29 16:09:28 +0200310 'androidx.test.espresso:espresso-core':'androidx.test.espresso.core',
311 'androidx.test.espresso:espresso-idling-resource':'androidx.test.espresso.idling-resource',
Alan Viverettecdfc9892021-08-31 19:35:58 +0000312}
313
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000314# List of artifacts that will be updated from GMaven
315# Use pattern: `group:library:version:extension`
316# e.g.:
317# androidx.appcompat:appcompat:1.2.0:aar
318# Use `latest` to always fetch the latest version.
319# e.g.:
320# androidx.appcompat:appcompat:latest:aar
321# Also make sure you add `group:library`:{} to maven_to_make as well.
322gmaven_artifacts = {}
Alan Viverettef3c12722021-08-30 19:50:33 +0000323
Alan Viverette95f6d362017-04-06 09:40:50 -0400324# Always remove these files.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000325denylist_files = [
Alan Viverette95f6d362017-04-06 09:40:50 -0400326 'annotations.zip',
327 'public.txt',
328 'R.txt',
Alan Viverette44ad4e42017-08-09 17:45:00 -0400329 'AndroidManifest.xml',
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000330 os.path.join('libs', 'noto-emoji-compat-java.jar')
Alan Viverette95f6d362017-04-06 09:40:50 -0400331]
332
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000333artifact_pattern = re.compile(r'^(.+?)-(\d+\.\d+\.\d+(?:-\w+\d+)?(?:-[\d.]+)*)\.(jar|aar)$')
Alan Viverette95f6d362017-04-06 09:40:50 -0400334
Alan Viverettec960cfb2017-12-04 13:09:22 -0500335
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000336def name_for_artifact(group_artifact):
337 """Returns the build system target name for a given library's Maven coordinate.
338
339 Args:
340 group_artifact: an unversioned Maven artifact coordinate, ex. androidx.core:core
341 Returns:
342 The build system target name for the artifact, ex. androidx.core_core.
343 """
344 return group_artifact.replace(':', '_')
Alan Viverettec960cfb2017-12-04 13:09:22 -0500345
346
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000347def path_for_artifact(group_artifact):
348 """Returns the file system path for a given library's Maven coordinate.
349
350 Args:
351 group_artifact: an unversioned Maven artifact coordinate, ex. androidx.core:core
352 Returns:
353 The file system path for the artifact, ex. androidx/core/core.
354 """
355 return group_artifact.replace('.', '/').replace(':', '/')
Alan Viverettef5cb0e62017-11-17 15:15:23 -0500356
Alan Viverette95f6d362017-04-06 09:40:50 -0400357
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000358def populate_maven_to_make(mapping):
359 """Modifies the input mapping by expanding Maven coordinate keys into build target names and
360 paths.
Alan Viverette95f6d362017-04-06 09:40:50 -0400361
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000362 Args:
363 mapping: a map where the keys are Maven coordinates
364 """
365 for key in mapping:
366 if 'name' not in mapping[key]:
367 mapping[key]['name'] = name_for_artifact(key)
368 if 'path' not in maven_to_make[key]:
369 mapping[key]['path'] = path_for_artifact(key)
Alan Viverette45837092017-05-12 14:50:53 -0400370
371
Jeff Gastonc302bb92018-03-23 13:53:48 -0400372def detect_artifacts(maven_repo_dirs):
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000373 """Parses Maven libraries from the specified directories.
374
375 Args:
376 maven_repo_dirs: a list of maven repository roots
377 Returns:
378 A map of Maven coordinate keys to MavenLibraryInfo objects parsed from POM files.
379 """
Alan Viveretted4527e62017-05-11 15:03:25 -0400380 maven_lib_info = {}
381
Dan Willemsen814152e2017-11-06 13:22:11 -0800382 # Find the latest revision for each artifact, remove others
Jeff Gastonc302bb92018-03-23 13:53:48 -0400383 for repo_dir in maven_repo_dirs:
Dan Willemsen814152e2017-11-06 13:22:11 -0800384 for root, dirs, files in os.walk(repo_dir):
385 for file in files:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000386 if file[-4:] == '.pom':
Alan Viverettec960cfb2017-12-04 13:09:22 -0500387 # Read the POM (hack hack hack).
388 group_id = ''
389 artifact_id = ''
390 version = ''
391 file = os.path.join(root, file)
392 with open(file) as pom_file:
393 for line in pom_file:
394 if line[:11] == ' <groupId>':
395 group_id = line[11:-11]
396 elif line[:14] == ' <artifactId>':
397 artifact_id = line[14:-14]
398 elif line[:11] == ' <version>':
399 version = line[11:-11]
400 if group_id == '' or artifact_id == '' or version == '':
401 print_e('Failed to find Maven artifact data in ' + file)
402 continue
Alan Viverette95f6d362017-04-06 09:40:50 -0400403
Alan Viverettec960cfb2017-12-04 13:09:22 -0500404 # Locate the artifact.
405 artifact_file = file[:-4]
406 if os.path.exists(artifact_file + '.jar'):
407 artifact_file = artifact_file + '.jar'
408 elif os.path.exists(artifact_file + '.aar'):
409 artifact_file = artifact_file + '.aar'
410 else:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000411 # This error only occurs for a handful of gradle.plugin artifacts that only
412 # ship POM files, so we probably don't need to log unless we're debugging.
413 # print_e('Failed to find artifact for ' + artifact_file)
Alan Viverettec960cfb2017-12-04 13:09:22 -0500414 continue
415
416 # Make relative to root.
417 artifact_file = artifact_file[len(root) + 1:]
418
419 # Find the mapping.
420 group_artifact = group_id + ':' + artifact_id
Jeff Gaston3e622ba2018-03-26 23:24:46 -0400421 if group_artifact in maven_to_make:
Alan Viverettec960cfb2017-12-04 13:09:22 -0500422 key = group_artifact
Jeff Gaston3e622ba2018-03-26 23:24:46 -0400423 elif artifact_id in maven_to_make:
424 key = artifact_id
Alan Viverettec960cfb2017-12-04 13:09:22 -0500425 else:
Alan Viverettecdfc9892021-08-31 19:35:58 +0000426 # No mapping entry, skip this library.
Alan Viverettec960cfb2017-12-04 13:09:22 -0500427 continue
428
429 # Store the latest version.
430 version = LooseVersion(version)
431 if key not in maven_lib_info \
432 or version > maven_lib_info[key].version:
433 maven_lib_info[key] = MavenLibraryInfo(key, group_id, artifact_id, version,
434 root, repo_dir, artifact_file)
Alan Viverette95f6d362017-04-06 09:40:50 -0400435
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400436 return maven_lib_info
437
438
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000439def transform_maven_repos(maven_repo_dirs, transformed_dir, extract_res=True,
440 include_static_deps=True, include=None, exclude=None, prepend=None):
441 """Transforms a standard Maven repository to be compatible with the Android build system.
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400442
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000443 When using the include argument by itself, all other libraries will be excluded. When using the
444 exclude argument by itself, all other libraries will be included. When using both arguments, the
445 inclusion list will be applied followed by the exclusion list.
446
447 Args:
448 maven_repo_dirs: path to local Maven repository
449 transformed_dir: relative path for output, ex. androidx
450 extract_res: whether to extract Android resources like AndroidManifest.xml from AARs
451 include_static_deps: whether to pass --static-deps to pom2bp
452 include: list of Maven groupIds or unversioned artifact coordinates to include for
453 updates, ex. androidx.core or androidx.core:core
454 exclude: list of Maven groupIds or unversioned artifact coordinates to exclude from
455 updates, ex. androidx.core or androidx.core:core
456 prepend: Path to a file containing text to be inserted at the beginning of the generated
457 build file
458 Returns:
459 True if successful, false otherwise.
460 """
461 if exclude is None:
462 exclude = []
463 if include is None:
464 include = []
465
466 cwd = os.getcwd()
467 local_repo = os.path.join(cwd, transformed_dir)
Jeff Gastona68a8d42018-03-23 14:00:13 -0400468 working_dir = temp_dir
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400469
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000470 # Handle inclusions by stashing the remote artifacts for the inclusions, replacing the entire
471 # remote repo with the local repo, then restoring the stashed artifacts.
472 for remote_repo in maven_repo_dirs:
473 remote_repo = os.path.join(cwd, remote_repo)
474 paths_to_copy = []
475 for group_artifact in include:
476 artifact_path = os.path.join('m2repository', path_for_artifact(group_artifact))
477 remote_path = os.path.join(remote_repo, artifact_path)
478 working_path = os.path.join(working_dir, artifact_path)
479 if os.path.exists(remote_path):
480 print(f'Included {group_artifact} in update')
481 paths_to_copy.append([remote_path, working_path])
482
483 # Move included artifacts from repo to temp.
484 for [remote_path, working_path] in paths_to_copy:
485 mv(remote_path, working_path)
486
487 # Replace all remaining artifacts in remote repo with local repo.
488 cp(local_repo, remote_repo)
489
490 # Restore included artifacts to remote repo.
491 for [remote_path, working_path] in paths_to_copy:
492 mv(working_path, remote_path)
493
494 # Handle exclusions by replacing the remote artifacts for the exclusions with local artifacts.
495 # This must happen before we parse the artifacts.
496 for remote_repo in maven_repo_dirs:
497 for group_artifact in exclude:
498 artifact_path = os.path.join('m2repository', path_for_artifact(group_artifact))
499 remote_path = os.path.join(remote_repo, artifact_path)
500 if os.path.exists(remote_path):
501 rm(remote_path)
502 local_path = os.path.join(local_repo, artifact_path)
503 if os.path.exists(local_path):
504 print(f'Excluded {group_artifact} from update, used local artifact')
505 mv(local_path, remote_path)
506 else:
507 print(f'Excluded {group_artifact} from update, no local artifact present')
508
509 # Parse artifacts.
510 maven_lib_info = detect_artifacts(maven_repo_dirs)
511
Alan Viverettec960cfb2017-12-04 13:09:22 -0500512 if not maven_lib_info:
513 print_e('Failed to detect artifacts')
514 return False
515
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000516 # Move libraries into the working directory, performing any necessary transformations.
Alan Viveretted4527e62017-05-11 15:03:25 -0400517 for info in maven_lib_info.values():
Alan Viveretted8ce7222017-12-11 17:24:43 -0500518 transform_maven_lib(working_dir, info, extract_res)
Dan Willemsen814152e2017-11-06 13:22:11 -0800519
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000520 # Generate a single Android.bp that specifies to use all of the above artifacts.
Colin Cross74683bc2018-04-11 17:36:18 -0700521 makefile = os.path.join(working_dir, 'Android.bp')
Alan Viverette4ec9a172018-02-20 16:19:31 -0500522 with open(makefile, 'w') as f:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000523 args = ['pom2bp']
524 args.extend(['-sdk-version', '31'])
525 args.extend(['-default-min-sdk-version', '24'])
Jeff Gaston1cc06092018-03-28 15:51:02 -0400526 if include_static_deps:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000527 args.append('-static-deps')
528 if prepend:
529 args.append(f'-prepend={prepend}')
530 rewrite_names = sorted(maven_to_make.keys())
531 args.extend([f'-rewrite=^{name}$={maven_to_make[name]["name"]}' for name in rewrite_names])
532 args.extend([f'-rewrite=^{key}$={value}' for key, value in deps_rewrite.items()])
533 args.extend(["-extra-static-libs=" + maven_to_make[name]['name'] + "=" + ",".join(
534 sorted(maven_to_make[name]['extra-static-libs'])) for name in maven_to_make if
535 'extra-static-libs' in maven_to_make[name]])
536 args.extend(["-optional-uses-libs=" + maven_to_make[name]['name'] + "=" + ",".join(
537 sorted(maven_to_make[name]['optional-uses-libs'])) for name in maven_to_make if
538 'optional-uses-libs' in maven_to_make[name]])
539 args.extend([f'-host={name}' for name in maven_to_make
540 if maven_to_make[name].get('host')])
541 args.extend([f'-host-and-device={name}' for name in maven_to_make
542 if maven_to_make[name].get('host_and_device')])
543 args.extend(['.'])
Dan Willemsen814152e2017-11-06 13:22:11 -0800544 subprocess.check_call(args, stdout=f, cwd=working_dir)
Alan Viverette95f6d362017-04-06 09:40:50 -0400545
546 # Replace the old directory.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000547 local_repo = os.path.join(cwd, transformed_dir)
548 mv(working_dir, local_repo)
Alan Viverettec960cfb2017-12-04 13:09:22 -0500549 return True
Alan Viverette95f6d362017-04-06 09:40:50 -0400550
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000551
Alan Viveretted8ce7222017-12-11 17:24:43 -0500552def transform_maven_lib(working_dir, artifact_info, extract_res):
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000553 """Transforms the specified artifact for use in the Android build system.
554
555 Moves relevant files for the artifact represented by artifact_info of type MavenLibraryInfo into
556 the appropriate path inside working_dir, unpacking files needed by the build system from AARs.
557
558 Args:
559 working_dir: The directory into which the artifact should be moved
560 artifact_info: A MavenLibraryInfo representing the library artifact
561 extract_res: True to extract resources from AARs, false otherwise.
562 """
Dan Willemsen814152e2017-11-06 13:22:11 -0800563 # Move library into working dir
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000564 new_dir = os.path.normpath(
565 os.path.join(working_dir, os.path.relpath(artifact_info.dir, artifact_info.repo_dir)))
Jeff Gastonc302bb92018-03-23 13:53:48 -0400566 mv(artifact_info.dir, new_dir)
Dan Willemsen814152e2017-11-06 13:22:11 -0800567
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000568 maven_lib_type = os.path.splitext(artifact_info.file)[1][1:]
Alan Viveretted4527e62017-05-11 15:03:25 -0400569
Alan Viverettef3c12722021-08-30 19:50:33 +0000570 group_artifact = artifact_info.key
571 make_lib_name = maven_to_make[group_artifact]['name']
572 make_dir_name = maven_to_make[group_artifact]['path']
Alan Viveretted4527e62017-05-11 15:03:25 -0400573
Alan Viverette129555e2018-01-30 09:57:57 -0500574 artifact_file = os.path.join(new_dir, artifact_info.file)
575
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000576 if maven_lib_type == 'aar':
Colin Cross59b59db2018-04-24 13:58:05 -0700577 if extract_res:
578 target_dir = os.path.join(working_dir, make_dir_name)
579 if not os.path.exists(target_dir):
580 os.makedirs(target_dir)
Dan Willemsen814152e2017-11-06 13:22:11 -0800581
Alan Viverettec960cfb2017-12-04 13:09:22 -0500582 process_aar(artifact_file, target_dir)
Alan Viveretted4527e62017-05-11 15:03:25 -0400583
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000584 with zipfile.ZipFile(artifact_file) as zip_file:
585 manifests_dir = os.path.join(working_dir, 'manifests')
586 zip_file.extract('AndroidManifest.xml', os.path.join(manifests_dir, make_lib_name))
Alan Viveretted4527e62017-05-11 15:03:25 -0400587
Alan Viverette95f6d362017-04-06 09:40:50 -0400588
Alan Viverettec960cfb2017-12-04 13:09:22 -0500589def process_aar(artifact_file, target_dir):
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000590 """Extracts and cleans up the contents of an AAR file to the specified directory.
591
592 Removes classes.jar, empty directories, and denylisted files.
593
594 Args:
595 artifact_file: path to the AAR to extract
596 target_dir: directory into which the contents should be extracted
597 """
Alan Viverette95f6d362017-04-06 09:40:50 -0400598 # Extract AAR file to target_dir.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000599 with zipfile.ZipFile(artifact_file) as zip_file:
600 zip_file.extractall(target_dir)
Alan Viverette95f6d362017-04-06 09:40:50 -0400601
Dan Willemsen814152e2017-11-06 13:22:11 -0800602 # Remove classes.jar
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000603 classes_jar = os.path.join(target_dir, 'classes.jar')
Alan Viverette95f6d362017-04-06 09:40:50 -0400604 if os.path.exists(classes_jar):
Dan Willemsen814152e2017-11-06 13:22:11 -0800605 os.remove(classes_jar)
Alan Viverette95f6d362017-04-06 09:40:50 -0400606
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000607 # Remove empty dirs.
608 for root, dirs, files in os.walk(target_dir, topdown=False):
609 for dir_name in dirs:
610 dir_path = os.path.join(root, dir_name)
Alan Viverette95f6d362017-04-06 09:40:50 -0400611 if not os.listdir(dir_path):
612 os.rmdir(dir_path)
613
614 # Remove top-level cruft.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000615 for file in denylist_files:
Alan Viverette95f6d362017-04-06 09:40:50 -0400616 file_path = os.path.join(target_dir, file)
617 if os.path.exists(file_path):
618 os.remove(file_path)
619
Alan Viverettef17c9402017-07-19 12:57:40 -0400620
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000621def fetch_gmaven_artifact(artifact):
622 """Fetch a GMaven artifact.
623
624 Downloads a GMaven artifact
625 (https://developer.android.com/studio/build/dependencies#gmaven-access)
626
627 Args:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000628 artifact: an instance of GMavenArtifact.
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000629 """
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000630 pom_path = maven_path_for_artifact(
631 'gmaven', artifact.group, artifact.library, artifact.version, 'pom')
632 artifact_path = maven_path_for_artifact(
633 'gmaven', artifact.group, artifact.library, artifact.version, artifact.ext)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000634
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000635 download_file_to_disk(artifact.get_pom_file_url(), pom_path)
636 download_file_to_disk(artifact.get_artifact_url(), artifact_path)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000637
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000638 return os.path.dirname(artifact_path)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000639
640
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000641def download_file_to_disk(url, filepath):
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000642 """Download the file at URL to the location dictated by the path.
643
644 Args:
645 url: Remote URL to download file from.
646 filepath: Filesystem path to write the file to.
647 """
648 print(f'Downloading URL: {url}')
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000649 file_data = request.urlopen(url)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000650
651 try:
652 os.makedirs(os.path.dirname(filepath))
653 except os.error:
654 # This is a common situation - os.makedirs fails if dir already exists.
655 pass
656 try:
657 with open(filepath, 'wb') as f:
658 f.write(six.ensure_binary(file_data.read()))
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000659 except Exception as e:
660 print_e(e.__class__, 'occurred while reading', filepath)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000661 os.remove(os.path.dirname(filepath))
662 raise
663
664
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000665def update_gmaven(gmaven_artifacts_list):
666 artifacts = [GMavenArtifact(artifact) for artifact in gmaven_artifacts_list]
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000667 for artifact in artifacts:
668 if artifact.version == 'latest':
669 artifact.version = artifact.get_latest_version()
670
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000671 if not transform_maven_repos(['gmaven'], gmaven_dir, extract_res=False):
672 return []
673 return [artifact.key for artifact in artifacts]
674
675
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000676def update_androidx(target, build_id, local_file, include, exclude, beyond_corp):
677 """Fetches and extracts Jetpack library prebuilts.
678
679 Args:
680 target: Android build server target name, must be specified if local_file is empty
681 build_id: Optional Android build server ID, must be specified if local_file is empty
682 local_file: Optional local top-of-tree ZIP, must be specified if build_id is empty
683 include: List of Maven groupIds or unversioned artifact coordinates to include for
684 updates, ex. android.core or androidx.core:core
685 exclude: List of Maven groupIds or unversioned artifact coordinates to exclude from
686 updates, ex. android.core or androidx.core:core
687 beyond_corp: Whether to use BeyondCorp-compatible artifact fetcher
688 Returns:
689 True if successful, false otherwise.
690 """
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400691 if build_id:
Anthony Chenacbb4872018-07-02 11:22:48 -0700692 repo_file = 'top-of-tree-m2repository-all-%s.zip' % build_id.fs_id
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000693 repo_dir = fetch_and_extract(target, build_id.url_id, repo_file, beyond_corp, None)
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400694 else:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000695 repo_dir = fetch_and_extract(target, None, None, beyond_corp, local_file)
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400696 if not repo_dir:
697 print_e('Failed to extract AndroidX repository')
698 return False
699
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000700 prepend_path = os.path.relpath('update_prebuilts/prepend_androidx_license', start=temp_dir)
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400701
Tony Mak0f658752019-07-19 11:11:05 +0100702 # Transform the repo archive into a Makefile-compatible format.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000703 if not transform_maven_repos([repo_dir], androidx_dir, extract_res=False, include=include,
704 exclude=exclude, prepend=prepend_path):
Tony Mak0f658752019-07-19 11:11:05 +0100705 return False
706
707 # Import JavaPlugins.bp in Android.bp.
708 makefile = os.path.join(androidx_dir, 'Android.bp')
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000709 with open(makefile, 'a+') as f:
Tony Mak0f658752019-07-19 11:11:05 +0100710 f.write('\nbuild = ["JavaPlugins.bp"]\n')
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000711
712 # Keep OWNERs file, JavaPlugins.bp file, and TEST_MAPPING files untouched.
Nick Anthonybac2fca2022-11-03 18:56:57 +0000713 files_to_restore = [androidx_owners, java_plugins_bp_path, test_mapping_file,
714 compose_test_mapping_file]
715 for file_to_restore in files_to_restore:
716 # Ignore any output or error - these files are not gauranteed to exist, but
717 # if they do, we want to restore them.
718 subprocess.call(['git', 'restore', file_to_restore],
719 stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
Tony Mak0f658752019-07-19 11:11:05 +0100720
721 return True
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400722
Alan Viverette6dc45752020-04-16 14:56:20 +0000723
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000724def update_jetifier(target, build_id, beyond_corp):
725 """
726 Fetches and extracts Jetifier tool prebuilts.
727
728 Args:
729 target: Android build server target name
730 build_id: Android build server ID
731 beyond_corp: Whether to use BeyondCorp-compatible artifact fetcher
732 Return:
733 Whether the prebuilt was successfully updated.
734 """
Jeff Gaston782c3e32018-02-06 14:36:17 -0500735 repo_file = 'jetifier-standalone.zip'
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000736 repo_dir = fetch_and_extract(target, build_id.url_id, repo_file, beyond_corp)
Jeff Gaston782c3e32018-02-06 14:36:17 -0500737 if not repo_dir:
738 print_e('Failed to extract Jetifier')
739 return False
740
741 rm(jetifier_dir)
Jeff Gaston553a4372018-03-29 18:34:22 -0400742 mv(os.path.join(repo_dir, 'jetifier-standalone'), jetifier_dir)
743 os.chmod(os.path.join(jetifier_dir, 'bin', 'jetifier-standalone'), 0o755)
Jeff Gaston782c3e32018-02-06 14:36:17 -0500744 return True
745
Alan Viverette7e897e22018-03-09 15:24:10 -0500746
Alan Viverette6dc45752020-04-16 14:56:20 +0000747def update_constraint(local_file):
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000748 """
749 Extracts ConstraintLayout library prebuilts.
750
751 Args:
752 local_file: local Maven repository ZIP containing library artifacts
753 Return:
754 Whether the prebuilts were successfully updated.
755 """
Jeff Gaston9edf86c2018-04-18 13:45:23 -0400756 repo_dir = extract_artifact(local_file)
757 if not repo_dir:
Alan Viverette6dc45752020-04-16 14:56:20 +0000758 print_e('Failed to extract Constraint Layout')
Jeff Gaston9edf86c2018-04-18 13:45:23 -0400759 return False
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000760 return transform_maven_repos([repo_dir], os.path.join(extras_dir, 'constraint-layout-x'),
761 extract_res=False)
Jeff Gaston9edf86c2018-04-18 13:45:23 -0400762
Alan Viverette45837092017-05-12 14:50:53 -0400763
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000764def update_material(local_file):
765 """
766 Extracts Material Design Components library prebuilts.
767
768 Args:
769 local_file: local Maven repository ZIP containing library artifacts
770 Return:
771 Whether the prebuilts were successfully updated.
772 """
773 design_dir = extract_artifact(local_file)
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400774 if not design_dir:
Alan Viverette6dc45752020-04-16 14:56:20 +0000775 print_e('Failed to extract Material Design Components')
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400776 return False
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000777 return transform_maven_repos([design_dir], os.path.join(extras_dir, 'material-design-x'),
778 extract_res=False)
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400779
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400780
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000781def update_framework(target, build_id, sdk_dir, beyond_corp):
Anton Hansson83f92172020-03-26 11:12:03 +0000782 api_scope_list = ['public', 'system', 'test', 'module-lib', 'system-server']
Sundong Ahn66091f22018-08-29 18:54:28 +0900783 if sdk_dir == 'current':
784 api_scope_list.append('core')
785
786 for api_scope in api_scope_list:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000787 target_dir = os.path.join(sdk_dir, api_scope)
Sundong Ahn66091f22018-08-29 18:54:28 +0900788 if api_scope == 'core':
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000789 artifact_to_path = {'core.current.stubs.jar': os.path.join(target_dir, 'android.jar')}
Sundong Ahn66091f22018-08-29 18:54:28 +0900790 else:
Paul Duffin6815a312021-10-28 13:02:51 +0100791 artifact_to_path = {
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000792 'apistubs/android/' + api_scope + '/*.jar': os.path.join(target_dir, '*'),
Paul Duffin6815a312021-10-28 13:02:51 +0100793 }
794 if api_scope == 'public' or api_scope == 'module-lib':
795 # Distinct core-for-system-modules.jar files are only provided
796 # for the public and module-lib API surfaces.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000797 artifact_to_path[
798 'system-modules/' + api_scope + '/core-for-system-modules.jar'] = os.path.join(
799 target_dir, '*')
Anton Hansson1d01a032018-04-09 10:29:37 +0100800
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000801 if not fetch_artifacts(target, build_id, artifact_to_path, beyond_corp):
Anton Hansson1d01a032018-04-09 10:29:37 +0100802 return False
803
Jiyong Park1d1c9632018-05-29 17:45:27 +0900804 if api_scope == 'public':
Anton Hansson1d01a032018-04-09 10:29:37 +0100805 # Fetch a few artifacts from the public sdk.
Sundong Ahn66091f22018-08-29 18:54:28 +0900806 artifact = 'sdk-repo-linux-platforms-%s.zip' % build_id.fs_id
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000807 artifact_path = fetch_artifact(target, build_id.url_id, artifact, beyond_corp)
Anton Hansson9709fd42018-04-03 16:52:13 +0100808 if not artifact_path:
809 return False
Anton Hansson1d01a032018-04-09 10:29:37 +0100810
811 with zipfile.ZipFile(artifact_path) as zipFile:
Colin Crossd338d702020-07-10 19:17:54 -0700812 extra_files = [
813 'android.jar',
814 'framework.aidl',
815 'uiautomator.jar',
Colin Crossd338d702020-07-10 19:17:54 -0700816 'data/annotations.zip',
817 'data/api-versions.xml']
818 for filename in extra_files:
Anton Hanssona26e4812020-03-25 12:54:39 +0000819 matches = list(filter(lambda path: filename in path, zipFile.namelist()))
820 if len(matches) != 1:
821 print_e('Expected 1 file named \'%s\' in zip %s, found %d' %
822 (filename, zipFile.filename, len(matches)))
823 return False
824 zip_path = matches[0]
825 src_path = zipFile.extract(zip_path)
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000826 dst_path = os.path.join(target_dir, filename)
Anton Hanssona26e4812020-03-25 12:54:39 +0000827 mv(src_path, dst_path)
Anton Hansson9709fd42018-04-03 16:52:13 +0100828
Anton Hansson73be1512021-06-24 10:56:05 +0100829 # Filtered API DB is currently only available for "public"
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000830 fetch_artifacts(target, build_id, {'api-versions-public-filtered.xml': os.path.join(
831 target_dir, 'data/api-versions-filtered.xml')}, beyond_corp)
Anton Hansson73be1512021-06-24 10:56:05 +0100832
Alan Viverettecd3de262017-08-14 09:51:30 -0400833 return True
Alan Viverette45837092017-05-12 14:50:53 -0400834
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000835
Sundong Ahncc34cc32018-07-11 15:18:47 +0900836def update_makefile(build_id):
837 template = '"%s",\n\
838 "current"'
839 makefile = os.path.join(git_dir, 'Android.bp')
840
841 with open(makefile, 'r+') as f:
842 contents = f.read().replace('"current"', template % build_id)
843 f.seek(0)
844 f.write(contents)
845
846 return True
Alan Viverette45837092017-05-12 14:50:53 -0400847
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000848
849def finalize_sdk(target, build_id, sdk_version, beyond_corp):
Anton Hansson1d01a032018-04-09 10:29:37 +0100850 target_finalize_dir = '%d' % sdk_version
Anton Hansson9709fd42018-04-03 16:52:13 +0100851
Anton Hanssonaa554c02020-04-30 14:06:20 +0100852 for api_scope in ['public', 'system', 'test', 'module-lib', 'system-server']:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000853 artifact_to_path = {f'apistubs/android/{api_scope}/api/*.txt': os.path.join(
854 target_finalize_dir, api_scope, 'api', '*')}
Sundong Ahn66091f22018-08-29 18:54:28 +0900855
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000856 if not fetch_artifacts(target, build_id, artifact_to_path, beyond_corp):
Sundong Ahn66091f22018-08-29 18:54:28 +0900857 return False
858
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000859 return update_framework(target, build_id, target_finalize_dir, beyond_corp) and update_makefile(
860 target_finalize_dir)
Anton Hansson9709fd42018-04-03 16:52:13 +0100861
Anton Hansson9709fd42018-04-03 16:52:13 +0100862
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000863def update_framework_current(target, build_id, beyond_corp):
864 return update_framework(target, build_id, current_path, beyond_corp)
Anton Hansson9709fd42018-04-03 16:52:13 +0100865
866
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000867def update_buildtools(target, arch, build_id, beyond_corp):
Jeff Gaston13e38412018-02-06 14:45:36 -0500868 artifact_path = fetch_and_extract(target, build_id.url_id,
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000869 f'sdk-repo-{arch}-build-tools-{build_id.fs_id}.zip',
870 beyond_corp)
Alan Viverettec1c32b62017-12-20 09:40:36 -0500871 if not artifact_path:
872 return False
873
874 top_level_dir = os.listdir(artifact_path)[0]
875 src_path = os.path.join(artifact_path, top_level_dir)
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000876 dst_path = os.path.join(buildtools_dir, arch)
Colin Cross20648d32021-02-12 13:30:51 -0800877
878 # There are a few libraries that have been manually added to the
879 # build tools, copy them from the destination back to the source
880 # before the destination is overwritten.
881 files_to_save = (
882 'lib64/libconscrypt_openjdk_jni.dylib',
883 'lib64/libconscrypt_openjdk_jni.so',
884 'bin/lib64/libwinpthread-1.dll',
885 )
886 for file in files_to_save:
887 src_file = os.path.join(dst_path, file)
888 dst_file = os.path.join(src_path, file)
889 if os.path.exists(dst_path):
890 mv(src_file, dst_file)
891
Alan Viverettec1c32b62017-12-20 09:40:36 -0500892 mv(src_path, dst_path)
893
894 # Move all top-level files to /bin and make them executable
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000895 bin_path = os.path.join(dst_path, 'bin')
896 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 -0500897 for file in top_level_files:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000898 src_file = os.path.join(dst_path, file)
899 dst_file = os.path.join(bin_path, file)
Alan Viverettec1c32b62017-12-20 09:40:36 -0500900 mv(src_file, dst_file)
901 os.chmod(dst_file, 0o755)
902
Colin Cross6673ceb2021-02-12 13:14:14 -0800903 # Make the files under lld-bin executable
904 lld_bin_files = os.listdir(os.path.join(dst_path, 'lld-bin'))
905 for file in lld_bin_files:
906 os.chmod(os.path.join(dst_path, 'lld-bin', file), 0o755)
907
Alan Viverettec1c32b62017-12-20 09:40:36 -0500908 # Remove renderscript
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000909 rm(os.path.join(dst_path, 'renderscript'))
Alan Viverettec1c32b62017-12-20 09:40:36 -0500910
911 return True
912
913
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000914def has_uncommitted_changes():
Jeff Gastoncc296a82018-03-23 14:33:24 -0400915 try:
916 # Make sure we don't overwrite any pending changes.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000917 diff_command = f'cd {git_dir} && git diff --quiet'
918 subprocess.check_call(diff_command, shell=True)
919 subprocess.check_call(f'{diff_command} --cached', shell=True)
Jeff Gastoncc296a82018-03-23 14:33:24 -0400920 return False
921 except subprocess.CalledProcessError:
922 return True
923
924
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000925def main():
926 parser = argparse.ArgumentParser(
927 description='Update current prebuilts')
928 parser.add_argument(
929 'source', nargs='?',
930 help='Build server build ID or local Maven ZIP file')
931 parser.add_argument(
932 '-m', '--material', action='store_true',
933 help='If specified, updates only Material Design Components')
934 parser.add_argument(
935 '-c', '--constraint', action='store_true',
936 help='If specified, updates only Constraint Layout')
937 parser.add_argument(
938 '-j', '--jetifier', action='store_true',
939 help='If specified, updates only Jetifier')
940 parser.add_argument(
941 '-p', '--platform', action='store_true',
942 help='If specified, updates only the Android Platform')
943 parser.add_argument(
944 '-f', '--finalize_sdk', type=int,
945 help='Finalize the build as the specified SDK version. Must be used together with -e')
946 parser.add_argument(
947 '-e', '--finalize_extension', type=int,
948 help='Finalize the build as the specified extension SDK version. Must be used together with -f')
949 parser.add_argument('--bug', type=int, help='The bug number to add to the commit message.')
950 parser.add_argument(
951 '--sdk_target',
952 default=framework_sdk_target,
953 help='If specified, the name of the build target from which to retrieve the SDK when -p or -f '
954 'is specified.')
955 parser.add_argument(
956 '-b', '--buildtools', action='store_true',
957 help='If specified, updates only the Build Tools')
958 parser.add_argument(
959 '-x', '--androidx', action='store_true',
960 help='If specified, updates only the Jetpack (androidx) libraries excluding those covered by '
961 'other arguments')
962 parser.add_argument(
963 '--include', action='append', default=[],
964 help='If specified with -x, includes the specified Jetpack library Maven group or artifact for '
965 'updates. Applied before exclude.')
966 parser.add_argument(
967 '--exclude', action='append', default=[],
968 help='If specified with -x, excludes the specified Jetpack library Maven group or artifact '
969 'from updates')
970 parser.add_argument(
971 '-g', '--gmaven', action='store_true',
972 help='If specified, updates only the artifact from GMaven libraries excluding those covered by '
973 'other arguments')
974 parser.add_argument(
975 '--commit-first', action='store_true',
976 help='If specified, then if uncommited changes exist, commit before continuing')
977 parser.add_argument(
978 '--beyond-corp', action='store_true',
979 help='If specified, then fetch artifacts with tooling that works on BeyondCorp devices')
Anton Hansson4bcebac2022-04-07 17:23:18 +0100980
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000981 rm(temp_dir)
Alan Viveretted4527e62017-05-11 15:03:25 -0400982
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000983 args = parser.parse_args()
Jeff Gastoncc296a82018-03-23 14:33:24 -0400984
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000985 # Validate combinations of arguments.
986 if not args.source and (args.platform or args.buildtools or args.jetifier
987 or args.androidx or args.material or args.finalize_sdk
988 or args.constraint):
989 parser.error('You must specify a build ID or local Maven ZIP file')
990 sys.exit(1)
991 if not (args.gmaven or args.platform or args.buildtools or args.jetifier
992 or args.androidx or args.material or args.finalize_sdk
993 or args.finalize_extension or args.constraint):
994 parser.error('You must specify at least one target to update')
995 sys.exit(1)
996 if (args.finalize_sdk is None) != (args.finalize_extension is None):
997 parser.error('Either both or neither of -e and -f must be specified.')
998 sys.exit(1)
999 if args.finalize_sdk and not args.bug:
1000 parser.error('Specifying a bug ID with --bug is required when finalizing an SDK.')
1001 sys.exit(1)
Alan Viveretted4527e62017-05-11 15:03:25 -04001002
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001003 # Validate the build environment for POM-dependent targets.
1004 if (args.constraint or args.material or args.androidx or args.gmaven) \
1005 and which('pom2bp') is None:
1006 parser.error('Cannot find pom2bp in path; please run lunch to set up build environment. '
1007 'You may also need to run \'m pom2bp\' if it hasn\'t been built already.')
1008 sys.exit(1)
Anton Hansson57a1b142022-04-07 17:27:41 +01001009
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001010 # Validate the git status.
1011 if has_uncommitted_changes():
1012 if args.commit_first:
1013 subprocess.check_call(f'cd {git_dir} && git add -u', shell=True)
1014 subprocess.check_call(f'cd {git_dir} && git commit -m \'save working state\'',
1015 shell=True)
1016 if has_uncommitted_changes():
1017 self_file = os.path.basename(__file__)
1018 print_e(f'FAIL: There are uncommitted changes here. Please commit or stash before '
1019 f'continuing, because {self_file} will run "git reset --hard" if execution fails')
1020 sys.exit(1)
Anton Hansson4bcebac2022-04-07 17:23:18 +01001021
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001022 if args.bug:
1023 commit_msg_suffix = '\n\nBug: {args.bug}'
Alan Viverette129555e2018-01-30 09:57:57 -05001024 else:
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001025 commit_msg_suffix = ''
Alan Viveretted4527e62017-05-11 15:03:25 -04001026
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001027 # Are we fetching a build ID or using a local file?
1028 build_id = None
1029 file = None
1030 if args.source:
1031 build_id = parse_build_id(args.source)
1032 if build_id is None:
1033 file = args.source
1034
Alan Viveretted4527e62017-05-11 15:03:25 -04001035 try:
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001036 components = []
1037 if args.constraint:
1038 if update_constraint(file):
1039 components.append('Constraint Layout')
1040 else:
1041 print_e('Failed to update Constraint Layout, aborting...')
1042 sys.exit(1)
1043 if args.material:
1044 if update_material(file):
1045 components.append('Material Design Components')
1046 else:
1047 print_e('Failed to update Material Design Components, aborting...')
1048 sys.exit(1)
1049 if args.gmaven:
1050 updated_artifacts = update_gmaven(gmaven_artifacts)
1051 if updated_artifacts:
1052 components.append('\n'.join(updated_artifacts))
1053 else:
1054 print_e('Failed to update GMaven, aborting...')
1055 sys.exit(1)
1056 if args.androidx:
1057 if update_androidx('androidx', build_id, file, args.include, args.exclude,
1058 args.beyond_corp):
1059 components.append('AndroidX')
1060 else:
1061 print_e('Failed to update AndroidX, aborting...')
1062 sys.exit(1)
1063 if args.jetifier:
1064 if update_jetifier('androidx', build_id, args.beyond_corp):
1065 components.append('Jetifier')
1066 else:
1067 print_e('Failed to update Jetifier, aborting...')
1068 sys.exit(1)
1069 if args.platform or args.finalize_sdk:
1070 if update_framework_current(args.sdk_target, build_id, args.beyond_corp):
1071 components.append('platform SDK')
1072 else:
1073 print_e('Failed to update platform SDK, aborting...')
1074 sys.exit(1)
1075 if args.finalize_sdk:
1076 n = args.finalize_sdk
1077 if not finalize_sdk(args.sdk_target, build_id, n, args.beyond_corp):
1078 print_e('Failed to finalize SDK %d, aborting...' % n)
1079 sys.exit(1)
1080
1081 # We commit the finalized dir separately from the current sdk update.
1082 msg = f'Import final sdk version {n} from build {build_id.url_id}{commit_msg_suffix}'
1083 subprocess.check_call(['git', 'add', '%d' % n])
1084 subprocess.check_call(['git', 'add', 'Android.bp'])
1085 subprocess.check_call(['git', 'commit', '-m', msg])
1086
1087 # Finalize extension sdk level
1088 readme = (f'- {args.finalize_extension}: Finalized together with '
1089 'Android {args.finalize_sdk} (all modules)')
1090 cmd = extension_sdk_finalization_cmd.format(
1091 readme=readme,
1092 bug=args.bug,
1093 extension_version=args.finalize_extension,
1094 build_id=build_id.url_id)
1095 subprocess.check_call(shlex.split(cmd), cwd=repo_root_dir.resolve())
1096 if args.buildtools:
1097 if update_buildtools('sdk_mac', 'darwin', build_id, args.beyond_corp) \
1098 and update_buildtools('sdk', 'linux', build_id, args.beyond_corp) \
1099 and update_buildtools('sdk', 'windows', build_id, args.beyond_corp):
1100 components.append('build tools')
1101 else:
1102 print_e('Failed to update build tools, aborting...')
1103 sys.exit(1)
1104
1105 # Build the git commit.
1106 subprocess.check_call(['git', 'add', current_path, buildtools_dir])
1107
1108 # Build the commit message.
1109 components_msg = ', '.join(components)
1110 argv_msg = ' '.join(sys.argv)
1111 if not args.source and args.gmaven:
1112 src_msg = 'GMaven'
1113 elif not args.source.isnumeric():
1114 src_msg = 'local Maven ZIP'
1115 else:
1116 src_msg = f'build {build_id.url_id}'
1117 msg = f'Import {components_msg} from {src_msg}\n\n{argv_msg}{commit_msg_suffix}'
1118
1119 # Create the git commit.
1120 subprocess.check_call(['git', 'commit', '-q', '-m', msg])
1121
1122 if args.finalize_sdk:
1123 print('NOTE: Created three commits:')
1124 subprocess.check_call(['git', 'log', '-3', '--oneline'])
1125 else:
1126 print('Created commit:')
1127 subprocess.check_call(['git', 'log', '-1', '--oneline'])
1128 print('Remember to test this change before uploading it to Gerrit!')
1129
1130 finally:
1131 # Revert all stray files, including the downloaded zip.
1132 try:
1133 with open(os.devnull, 'w') as bitbucket:
1134 subprocess.check_call(['git', 'add', '-Af', '.'], stdout=bitbucket)
1135 subprocess.check_call(
1136 ['git', 'commit', '-m', 'COMMIT TO REVERT - RESET ME!!!', '--allow-empty'],
1137 stdout=bitbucket)
1138 subprocess.check_call(['git', 'reset', '--hard', 'HEAD~1'], stdout=bitbucket)
1139 except subprocess.CalledProcessError:
1140 print_e('ERROR: Failed cleaning up, manual cleanup required!!!')
1141
1142
1143# Add automatic entries to maven_to_make.
1144populate_maven_to_make(maven_to_make)
1145
1146if __name__ == '__main__':
1147 main()