blob: 2d1d28e1b07e9296c64071d05ca202507a415e69 [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 },
Anvesh Renikindi495d5c62023-02-07 01:31:10 +0000187 'androidx.window.extensions:extensions': {},
188 'androidx.window.extensions.core:core': {},
189 'androidx.window:window-core': {},
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000190 'androidx.resourceinspection:resourceinspection-annotation': {},
191 'androidx.profileinstaller:profileinstaller': {},
192 'androidx.test.uiautomator:uiautomator': {},
Aurimas Liutikas6e87bbf2021-07-30 10:04:05 -0700193
Alan Viverettef44e2f92021-08-31 17:26:26 +0000194 # AndroidX for Compose
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000195 'androidx.compose.compiler:compiler-hosted': {
196 'host': True
197 },
198 'androidx.compose.runtime:runtime': {},
199 'androidx.compose.runtime:runtime-saveable': {},
200 'androidx.compose.runtime:runtime-livedata': {},
Jordan Demeulenaere13e19082022-11-24 17:43:06 +0100201 'androidx.compose.runtime:runtime-tracing': {},
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000202 'androidx.compose.foundation:foundation': {},
203 'androidx.compose.foundation:foundation-layout': {},
204 'androidx.compose.foundation:foundation-text': {},
205 'androidx.compose.ui:ui': {},
206 'androidx.compose.ui:ui-geometry': {},
207 'androidx.compose.ui:ui-graphics': {},
208 'androidx.compose.ui:ui-text': {},
209 'androidx.compose.ui:ui-tooling': {},
210 'androidx.compose.ui:ui-tooling-preview': {},
211 'androidx.compose.ui:ui-tooling-data': {},
212 'androidx.compose.ui:ui-unit': {},
213 'androidx.compose.ui:ui-util': {},
Jordan Demeulenaere606dca92022-07-29 16:09:28 +0200214 'androidx.compose.ui:ui-test': { },
215 'androidx.compose.ui:ui-test-junit4': { },
Jordan Demeulenaere76170242022-05-16 12:18:39 +0200216 'androidx.compose.ui:ui-test-manifest': { },
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000217 'androidx.compose.animation:animation-core': {},
218 'androidx.compose.animation:animation': {},
219 'androidx.compose.material:material-icons-core': {},
Jordan Demeulenaere606dca92022-07-29 16:09:28 +0200220 'androidx.compose.material:material-icons-extended': { },
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000221 'androidx.compose.material:material-ripple': {},
222 'androidx.compose.material:material': {},
223 'androidx.compose.material3:material3': {},
224 'androidx.activity:activity-compose': {},
Jordan Demeulenaere606dca92022-07-29 16:09:28 +0200225 'androidx.navigation:navigation-compose': { },
226 'androidx.lifecycle:lifecycle-viewmodel-compose': { },
Alan Viverettef44e2f92021-08-31 17:26:26 +0000227
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400228 # AndroidX for Multidex
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000229 'androidx.multidex:multidex': {},
230 'androidx.multidex:multidex-instrumentation': {},
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400231
232 # AndroidX for Constraint Layout
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000233 'androidx.constraintlayout:constraintlayout': {
234 'name': 'androidx-constraintlayout_constraintlayout'
235 },
236 'androidx.constraintlayout:constraintlayout-solver': {
237 'name': 'androidx-constraintlayout_constraintlayout-solver'
238 },
Anvesh Renikindi82b59882022-11-22 01:33:01 +0000239 'androidx.constraintlayout:constraintlayout-core': {},
240 'androidx.constraintlayout:constraintlayout-compose': {},
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400241 # AndroidX for Architecture Components
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000242 'androidx.arch.core:core-common': {},
243 'androidx.arch.core:core-runtime': {},
244 'androidx.lifecycle:lifecycle-common': {},
245 'androidx.lifecycle:lifecycle-common-java8': {},
246 'androidx.lifecycle:lifecycle-extensions': {},
247 'androidx.lifecycle:lifecycle-livedata': {},
248 'androidx.lifecycle:lifecycle-livedata-ktx': {},
249 'androidx.lifecycle:lifecycle-livedata-core': {},
250 'androidx.lifecycle:lifecycle-livedata-core-ktx': {},
251 'androidx.lifecycle:lifecycle-process': {},
252 'androidx.lifecycle:lifecycle-runtime': {},
253 'androidx.lifecycle:lifecycle-runtime-ktx': {},
254 'androidx.lifecycle:lifecycle-service': {},
255 'androidx.lifecycle:lifecycle-viewmodel': {},
256 'androidx.lifecycle:lifecycle-viewmodel-ktx': {},
257 'androidx.lifecycle:lifecycle-viewmodel-savedstate': {},
258 'androidx.paging:paging-common': {},
259 'androidx.paging:paging-common-ktx': {},
260 'androidx.paging:paging-runtime': {},
261 'androidx.sqlite:sqlite': {},
262 'androidx.sqlite:sqlite-framework': {},
263 'androidx.room:room-common': {
264 'host_and_device': True
265 },
266 'androidx.room:room-compiler': {
267 'host': True,
268 'extra-static-libs': {
Krzysztof Kosiński2450c552022-11-04 21:35:51 +0000269 'guava'
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000270 }
271 },
272 'androidx.room:room-migration': {
273 'host_and_device': True
274 },
275 'androidx.room:room-runtime': {},
276 'androidx.room:room-testing': {},
277 'androidx.room:room-compiler-processing': {
278 'host': True
279 },
280 'androidx.work:work-runtime': {},
281 'androidx.work:work-runtime-ktx': {},
282 'androidx.work:work-testing': {},
Allenab72f012018-01-29 18:10:23 -0800283
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400284 # Third-party dependencies
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000285 'com.google.android:flexbox': {
286 'name': 'flexbox',
287 'path': 'flexbox'
288 },
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400289
Jeff Gastonfa7c7e82018-04-06 13:35:48 -0400290 # Androidx Material Design Components
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000291 'com.google.android.material:material': {},
Alan Viverette95f6d362017-04-06 09:40:50 -0400292}
293
Alan Viverettecdfc9892021-08-31 19:35:58 +0000294# Mapping of POM dependencies to Soong build targets
295deps_rewrite = {
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000296 'auto-common': 'auto_common',
297 'auto-value-annotations': 'auto_value_annotations',
298 'com.google.auto.value:auto-value': 'libauto_value_plugin',
299 'monitor': 'androidx.test.monitor',
300 'rules': 'androidx.test.rules',
301 'runner': 'androidx.test.runner',
302 'androidx.test:core': 'androidx.test.core',
303 'com.squareup:javapoet': 'javapoet',
304 'com.google.guava:listenablefuture': 'guava-listenablefuture-prebuilt-jar',
305 'sqlite-jdbc': 'xerial-sqlite-jdbc',
306 'com.intellij:annotations': 'jetbrains-annotations',
307 'javax.annotation:javax.annotation-api': 'javax-annotation-api-prebuilt-host-jar',
308 'org.robolectric:robolectric': 'Robolectric_all-target',
309 'org.jetbrains.kotlin:kotlin-stdlib-common': 'kotlin-stdlib',
310 'org.jetbrains.kotlinx:kotlinx-coroutines-core': 'kotlinx_coroutines',
311 'org.jetbrains.kotlinx:kotlinx-coroutines-android': 'kotlinx_coroutines_android',
Jordan Demeulenaere606dca92022-07-29 16:09:28 +0200312 'org.jetbrains.kotlinx:kotlinx-coroutines-test':'kotlinx_coroutines_test',
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000313 'org.jetbrains.kotlinx:kotlinx-metadata-jvm': 'kotlinx_metadata_jvm',
Jordan Demeulenaere606dca92022-07-29 16:09:28 +0200314 'androidx.test.espresso:espresso-core':'androidx.test.espresso.core',
315 'androidx.test.espresso:espresso-idling-resource':'androidx.test.espresso.idling-resource',
Alan Viverettecdfc9892021-08-31 19:35:58 +0000316}
317
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000318# List of artifacts that will be updated from GMaven
319# Use pattern: `group:library:version:extension`
320# e.g.:
321# androidx.appcompat:appcompat:1.2.0:aar
322# Use `latest` to always fetch the latest version.
323# e.g.:
324# androidx.appcompat:appcompat:latest:aar
325# Also make sure you add `group:library`:{} to maven_to_make as well.
326gmaven_artifacts = {}
Alan Viverettef3c12722021-08-30 19:50:33 +0000327
Alan Viverette95f6d362017-04-06 09:40:50 -0400328# Always remove these files.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000329denylist_files = [
Alan Viverette95f6d362017-04-06 09:40:50 -0400330 'annotations.zip',
331 'public.txt',
332 'R.txt',
Alan Viverette44ad4e42017-08-09 17:45:00 -0400333 'AndroidManifest.xml',
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000334 os.path.join('libs', 'noto-emoji-compat-java.jar')
Alan Viverette95f6d362017-04-06 09:40:50 -0400335]
336
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000337artifact_pattern = re.compile(r'^(.+?)-(\d+\.\d+\.\d+(?:-\w+\d+)?(?:-[\d.]+)*)\.(jar|aar)$')
Alan Viverette95f6d362017-04-06 09:40:50 -0400338
Alan Viverettec960cfb2017-12-04 13:09:22 -0500339
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000340def name_for_artifact(group_artifact):
341 """Returns the build system target name for a given library's Maven coordinate.
342
343 Args:
344 group_artifact: an unversioned Maven artifact coordinate, ex. androidx.core:core
345 Returns:
346 The build system target name for the artifact, ex. androidx.core_core.
347 """
348 return group_artifact.replace(':', '_')
Alan Viverettec960cfb2017-12-04 13:09:22 -0500349
350
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000351def path_for_artifact(group_artifact):
352 """Returns the file system path for a given library's Maven coordinate.
353
354 Args:
355 group_artifact: an unversioned Maven artifact coordinate, ex. androidx.core:core
356 Returns:
357 The file system path for the artifact, ex. androidx/core/core.
358 """
359 return group_artifact.replace('.', '/').replace(':', '/')
Alan Viverettef5cb0e62017-11-17 15:15:23 -0500360
Alan Viverette95f6d362017-04-06 09:40:50 -0400361
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000362def populate_maven_to_make(mapping):
363 """Modifies the input mapping by expanding Maven coordinate keys into build target names and
364 paths.
Alan Viverette95f6d362017-04-06 09:40:50 -0400365
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000366 Args:
367 mapping: a map where the keys are Maven coordinates
368 """
369 for key in mapping:
370 if 'name' not in mapping[key]:
371 mapping[key]['name'] = name_for_artifact(key)
372 if 'path' not in maven_to_make[key]:
373 mapping[key]['path'] = path_for_artifact(key)
Alan Viverette45837092017-05-12 14:50:53 -0400374
375
Jeff Gastonc302bb92018-03-23 13:53:48 -0400376def detect_artifacts(maven_repo_dirs):
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000377 """Parses Maven libraries from the specified directories.
378
379 Args:
380 maven_repo_dirs: a list of maven repository roots
381 Returns:
382 A map of Maven coordinate keys to MavenLibraryInfo objects parsed from POM files.
383 """
Alan Viveretted4527e62017-05-11 15:03:25 -0400384 maven_lib_info = {}
385
Dan Willemsen814152e2017-11-06 13:22:11 -0800386 # Find the latest revision for each artifact, remove others
Jeff Gastonc302bb92018-03-23 13:53:48 -0400387 for repo_dir in maven_repo_dirs:
Dan Willemsen814152e2017-11-06 13:22:11 -0800388 for root, dirs, files in os.walk(repo_dir):
389 for file in files:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000390 if file[-4:] == '.pom':
Alan Viverettec960cfb2017-12-04 13:09:22 -0500391 # Read the POM (hack hack hack).
392 group_id = ''
393 artifact_id = ''
394 version = ''
395 file = os.path.join(root, file)
396 with open(file) as pom_file:
397 for line in pom_file:
398 if line[:11] == ' <groupId>':
399 group_id = line[11:-11]
400 elif line[:14] == ' <artifactId>':
401 artifact_id = line[14:-14]
402 elif line[:11] == ' <version>':
403 version = line[11:-11]
404 if group_id == '' or artifact_id == '' or version == '':
405 print_e('Failed to find Maven artifact data in ' + file)
406 continue
Alan Viverette95f6d362017-04-06 09:40:50 -0400407
Alan Viverettec960cfb2017-12-04 13:09:22 -0500408 # Locate the artifact.
409 artifact_file = file[:-4]
410 if os.path.exists(artifact_file + '.jar'):
411 artifact_file = artifact_file + '.jar'
412 elif os.path.exists(artifact_file + '.aar'):
413 artifact_file = artifact_file + '.aar'
414 else:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000415 # This error only occurs for a handful of gradle.plugin artifacts that only
416 # ship POM files, so we probably don't need to log unless we're debugging.
417 # print_e('Failed to find artifact for ' + artifact_file)
Alan Viverettec960cfb2017-12-04 13:09:22 -0500418 continue
419
420 # Make relative to root.
421 artifact_file = artifact_file[len(root) + 1:]
422
423 # Find the mapping.
424 group_artifact = group_id + ':' + artifact_id
Jeff Gaston3e622ba2018-03-26 23:24:46 -0400425 if group_artifact in maven_to_make:
Alan Viverettec960cfb2017-12-04 13:09:22 -0500426 key = group_artifact
Jeff Gaston3e622ba2018-03-26 23:24:46 -0400427 elif artifact_id in maven_to_make:
428 key = artifact_id
Alan Viverettec960cfb2017-12-04 13:09:22 -0500429 else:
Alan Viverettecdfc9892021-08-31 19:35:58 +0000430 # No mapping entry, skip this library.
Alan Viverettec960cfb2017-12-04 13:09:22 -0500431 continue
432
433 # Store the latest version.
434 version = LooseVersion(version)
435 if key not in maven_lib_info \
436 or version > maven_lib_info[key].version:
437 maven_lib_info[key] = MavenLibraryInfo(key, group_id, artifact_id, version,
438 root, repo_dir, artifact_file)
Alan Viverette95f6d362017-04-06 09:40:50 -0400439
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400440 return maven_lib_info
441
442
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000443def transform_maven_repos(maven_repo_dirs, transformed_dir, extract_res=True,
444 include_static_deps=True, include=None, exclude=None, prepend=None):
445 """Transforms a standard Maven repository to be compatible with the Android build system.
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400446
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000447 When using the include argument by itself, all other libraries will be excluded. When using the
448 exclude argument by itself, all other libraries will be included. When using both arguments, the
449 inclusion list will be applied followed by the exclusion list.
450
451 Args:
452 maven_repo_dirs: path to local Maven repository
453 transformed_dir: relative path for output, ex. androidx
454 extract_res: whether to extract Android resources like AndroidManifest.xml from AARs
455 include_static_deps: whether to pass --static-deps to pom2bp
456 include: list of Maven groupIds or unversioned artifact coordinates to include for
457 updates, ex. androidx.core or androidx.core:core
458 exclude: list of Maven groupIds or unversioned artifact coordinates to exclude from
459 updates, ex. androidx.core or androidx.core:core
460 prepend: Path to a file containing text to be inserted at the beginning of the generated
461 build file
462 Returns:
463 True if successful, false otherwise.
464 """
465 if exclude is None:
466 exclude = []
467 if include is None:
468 include = []
469
470 cwd = os.getcwd()
471 local_repo = os.path.join(cwd, transformed_dir)
Jeff Gastona68a8d42018-03-23 14:00:13 -0400472 working_dir = temp_dir
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400473
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000474 # Handle inclusions by stashing the remote artifacts for the inclusions, replacing the entire
475 # remote repo with the local repo, then restoring the stashed artifacts.
476 for remote_repo in maven_repo_dirs:
477 remote_repo = os.path.join(cwd, remote_repo)
478 paths_to_copy = []
479 for group_artifact in include:
480 artifact_path = os.path.join('m2repository', path_for_artifact(group_artifact))
481 remote_path = os.path.join(remote_repo, artifact_path)
482 working_path = os.path.join(working_dir, artifact_path)
483 if os.path.exists(remote_path):
484 print(f'Included {group_artifact} in update')
485 paths_to_copy.append([remote_path, working_path])
486
487 # Move included artifacts from repo to temp.
488 for [remote_path, working_path] in paths_to_copy:
489 mv(remote_path, working_path)
490
491 # Replace all remaining artifacts in remote repo with local repo.
492 cp(local_repo, remote_repo)
493
494 # Restore included artifacts to remote repo.
495 for [remote_path, working_path] in paths_to_copy:
496 mv(working_path, remote_path)
497
498 # Handle exclusions by replacing the remote artifacts for the exclusions with local artifacts.
499 # This must happen before we parse the artifacts.
500 for remote_repo in maven_repo_dirs:
501 for group_artifact in exclude:
502 artifact_path = os.path.join('m2repository', path_for_artifact(group_artifact))
503 remote_path = os.path.join(remote_repo, artifact_path)
504 if os.path.exists(remote_path):
505 rm(remote_path)
506 local_path = os.path.join(local_repo, artifact_path)
507 if os.path.exists(local_path):
508 print(f'Excluded {group_artifact} from update, used local artifact')
509 mv(local_path, remote_path)
510 else:
511 print(f'Excluded {group_artifact} from update, no local artifact present')
512
513 # Parse artifacts.
514 maven_lib_info = detect_artifacts(maven_repo_dirs)
515
Alan Viverettec960cfb2017-12-04 13:09:22 -0500516 if not maven_lib_info:
517 print_e('Failed to detect artifacts')
518 return False
519
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000520 # Move libraries into the working directory, performing any necessary transformations.
Alan Viveretted4527e62017-05-11 15:03:25 -0400521 for info in maven_lib_info.values():
Alan Viveretted8ce7222017-12-11 17:24:43 -0500522 transform_maven_lib(working_dir, info, extract_res)
Dan Willemsen814152e2017-11-06 13:22:11 -0800523
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000524 # Generate a single Android.bp that specifies to use all of the above artifacts.
Colin Cross74683bc2018-04-11 17:36:18 -0700525 makefile = os.path.join(working_dir, 'Android.bp')
Alan Viverette4ec9a172018-02-20 16:19:31 -0500526 with open(makefile, 'w') as f:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000527 args = ['pom2bp']
528 args.extend(['-sdk-version', '31'])
529 args.extend(['-default-min-sdk-version', '24'])
Jeff Gaston1cc06092018-03-28 15:51:02 -0400530 if include_static_deps:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000531 args.append('-static-deps')
532 if prepend:
533 args.append(f'-prepend={prepend}')
534 rewrite_names = sorted(maven_to_make.keys())
535 args.extend([f'-rewrite=^{name}$={maven_to_make[name]["name"]}' for name in rewrite_names])
536 args.extend([f'-rewrite=^{key}$={value}' for key, value in deps_rewrite.items()])
537 args.extend(["-extra-static-libs=" + maven_to_make[name]['name'] + "=" + ",".join(
538 sorted(maven_to_make[name]['extra-static-libs'])) for name in maven_to_make if
539 'extra-static-libs' in maven_to_make[name]])
540 args.extend(["-optional-uses-libs=" + maven_to_make[name]['name'] + "=" + ",".join(
541 sorted(maven_to_make[name]['optional-uses-libs'])) for name in maven_to_make if
542 'optional-uses-libs' in maven_to_make[name]])
543 args.extend([f'-host={name}' for name in maven_to_make
544 if maven_to_make[name].get('host')])
545 args.extend([f'-host-and-device={name}' for name in maven_to_make
546 if maven_to_make[name].get('host_and_device')])
547 args.extend(['.'])
Dan Willemsen814152e2017-11-06 13:22:11 -0800548 subprocess.check_call(args, stdout=f, cwd=working_dir)
Alan Viverette95f6d362017-04-06 09:40:50 -0400549
550 # Replace the old directory.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000551 local_repo = os.path.join(cwd, transformed_dir)
552 mv(working_dir, local_repo)
Alan Viverettec960cfb2017-12-04 13:09:22 -0500553 return True
Alan Viverette95f6d362017-04-06 09:40:50 -0400554
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000555
Alan Viveretted8ce7222017-12-11 17:24:43 -0500556def transform_maven_lib(working_dir, artifact_info, extract_res):
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000557 """Transforms the specified artifact for use in the Android build system.
558
559 Moves relevant files for the artifact represented by artifact_info of type MavenLibraryInfo into
560 the appropriate path inside working_dir, unpacking files needed by the build system from AARs.
561
562 Args:
563 working_dir: The directory into which the artifact should be moved
564 artifact_info: A MavenLibraryInfo representing the library artifact
565 extract_res: True to extract resources from AARs, false otherwise.
566 """
Dan Willemsen814152e2017-11-06 13:22:11 -0800567 # Move library into working dir
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000568 new_dir = os.path.normpath(
569 os.path.join(working_dir, os.path.relpath(artifact_info.dir, artifact_info.repo_dir)))
Jeff Gastonc302bb92018-03-23 13:53:48 -0400570 mv(artifact_info.dir, new_dir)
Dan Willemsen814152e2017-11-06 13:22:11 -0800571
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000572 maven_lib_type = os.path.splitext(artifact_info.file)[1][1:]
Alan Viveretted4527e62017-05-11 15:03:25 -0400573
Alan Viverettef3c12722021-08-30 19:50:33 +0000574 group_artifact = artifact_info.key
575 make_lib_name = maven_to_make[group_artifact]['name']
576 make_dir_name = maven_to_make[group_artifact]['path']
Alan Viveretted4527e62017-05-11 15:03:25 -0400577
Alan Viverette129555e2018-01-30 09:57:57 -0500578 artifact_file = os.path.join(new_dir, artifact_info.file)
579
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000580 if maven_lib_type == 'aar':
Colin Cross59b59db2018-04-24 13:58:05 -0700581 if extract_res:
582 target_dir = os.path.join(working_dir, make_dir_name)
583 if not os.path.exists(target_dir):
584 os.makedirs(target_dir)
Dan Willemsen814152e2017-11-06 13:22:11 -0800585
Alan Viverettec960cfb2017-12-04 13:09:22 -0500586 process_aar(artifact_file, target_dir)
Alan Viveretted4527e62017-05-11 15:03:25 -0400587
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000588 with zipfile.ZipFile(artifact_file) as zip_file:
589 manifests_dir = os.path.join(working_dir, 'manifests')
590 zip_file.extract('AndroidManifest.xml', os.path.join(manifests_dir, make_lib_name))
Alan Viveretted4527e62017-05-11 15:03:25 -0400591
Alan Viverette95f6d362017-04-06 09:40:50 -0400592
Alan Viverettec960cfb2017-12-04 13:09:22 -0500593def process_aar(artifact_file, target_dir):
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000594 """Extracts and cleans up the contents of an AAR file to the specified directory.
595
596 Removes classes.jar, empty directories, and denylisted files.
597
598 Args:
599 artifact_file: path to the AAR to extract
600 target_dir: directory into which the contents should be extracted
601 """
Alan Viverette95f6d362017-04-06 09:40:50 -0400602 # Extract AAR file to target_dir.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000603 with zipfile.ZipFile(artifact_file) as zip_file:
604 zip_file.extractall(target_dir)
Alan Viverette95f6d362017-04-06 09:40:50 -0400605
Dan Willemsen814152e2017-11-06 13:22:11 -0800606 # Remove classes.jar
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000607 classes_jar = os.path.join(target_dir, 'classes.jar')
Alan Viverette95f6d362017-04-06 09:40:50 -0400608 if os.path.exists(classes_jar):
Dan Willemsen814152e2017-11-06 13:22:11 -0800609 os.remove(classes_jar)
Alan Viverette95f6d362017-04-06 09:40:50 -0400610
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000611 # Remove empty dirs.
612 for root, dirs, files in os.walk(target_dir, topdown=False):
613 for dir_name in dirs:
614 dir_path = os.path.join(root, dir_name)
Alan Viverette95f6d362017-04-06 09:40:50 -0400615 if not os.listdir(dir_path):
616 os.rmdir(dir_path)
617
618 # Remove top-level cruft.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000619 for file in denylist_files:
Alan Viverette95f6d362017-04-06 09:40:50 -0400620 file_path = os.path.join(target_dir, file)
621 if os.path.exists(file_path):
622 os.remove(file_path)
623
Alan Viverettef17c9402017-07-19 12:57:40 -0400624
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000625def fetch_gmaven_artifact(artifact):
626 """Fetch a GMaven artifact.
627
628 Downloads a GMaven artifact
629 (https://developer.android.com/studio/build/dependencies#gmaven-access)
630
631 Args:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000632 artifact: an instance of GMavenArtifact.
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000633 """
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000634 pom_path = maven_path_for_artifact(
635 'gmaven', artifact.group, artifact.library, artifact.version, 'pom')
636 artifact_path = maven_path_for_artifact(
637 'gmaven', artifact.group, artifact.library, artifact.version, artifact.ext)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000638
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000639 download_file_to_disk(artifact.get_pom_file_url(), pom_path)
640 download_file_to_disk(artifact.get_artifact_url(), artifact_path)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000641
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000642 return os.path.dirname(artifact_path)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000643
644
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000645def download_file_to_disk(url, filepath):
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000646 """Download the file at URL to the location dictated by the path.
647
648 Args:
649 url: Remote URL to download file from.
650 filepath: Filesystem path to write the file to.
651 """
652 print(f'Downloading URL: {url}')
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000653 file_data = request.urlopen(url)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000654
655 try:
656 os.makedirs(os.path.dirname(filepath))
657 except os.error:
658 # This is a common situation - os.makedirs fails if dir already exists.
659 pass
660 try:
661 with open(filepath, 'wb') as f:
662 f.write(six.ensure_binary(file_data.read()))
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000663 except Exception as e:
664 print_e(e.__class__, 'occurred while reading', filepath)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000665 os.remove(os.path.dirname(filepath))
666 raise
667
668
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000669def update_gmaven(gmaven_artifacts_list):
670 artifacts = [GMavenArtifact(artifact) for artifact in gmaven_artifacts_list]
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000671 for artifact in artifacts:
672 if artifact.version == 'latest':
673 artifact.version = artifact.get_latest_version()
674
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000675 if not transform_maven_repos(['gmaven'], gmaven_dir, extract_res=False):
676 return []
677 return [artifact.key for artifact in artifacts]
678
679
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000680def update_androidx(target, build_id, local_file, include, exclude, beyond_corp):
681 """Fetches and extracts Jetpack library prebuilts.
682
683 Args:
684 target: Android build server target name, must be specified if local_file is empty
685 build_id: Optional Android build server ID, must be specified if local_file is empty
686 local_file: Optional local top-of-tree ZIP, must be specified if build_id is empty
687 include: List of Maven groupIds or unversioned artifact coordinates to include for
688 updates, ex. android.core or androidx.core:core
689 exclude: List of Maven groupIds or unversioned artifact coordinates to exclude from
690 updates, ex. android.core or androidx.core:core
691 beyond_corp: Whether to use BeyondCorp-compatible artifact fetcher
692 Returns:
693 True if successful, false otherwise.
694 """
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400695 if build_id:
Anthony Chenacbb4872018-07-02 11:22:48 -0700696 repo_file = 'top-of-tree-m2repository-all-%s.zip' % build_id.fs_id
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000697 repo_dir = fetch_and_extract(target, build_id.url_id, repo_file, beyond_corp, None)
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400698 else:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000699 repo_dir = fetch_and_extract(target, None, None, beyond_corp, local_file)
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400700 if not repo_dir:
701 print_e('Failed to extract AndroidX repository')
702 return False
703
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000704 prepend_path = os.path.relpath('update_prebuilts/prepend_androidx_license', start=temp_dir)
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400705
Tony Mak0f658752019-07-19 11:11:05 +0100706 # Transform the repo archive into a Makefile-compatible format.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000707 if not transform_maven_repos([repo_dir], androidx_dir, extract_res=False, include=include,
708 exclude=exclude, prepend=prepend_path):
Tony Mak0f658752019-07-19 11:11:05 +0100709 return False
710
711 # Import JavaPlugins.bp in Android.bp.
712 makefile = os.path.join(androidx_dir, 'Android.bp')
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000713 with open(makefile, 'a+') as f:
Tony Mak0f658752019-07-19 11:11:05 +0100714 f.write('\nbuild = ["JavaPlugins.bp"]\n')
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000715
716 # Keep OWNERs file, JavaPlugins.bp file, and TEST_MAPPING files untouched.
Nick Anthonybac2fca2022-11-03 18:56:57 +0000717 files_to_restore = [androidx_owners, java_plugins_bp_path, test_mapping_file,
718 compose_test_mapping_file]
719 for file_to_restore in files_to_restore:
720 # Ignore any output or error - these files are not gauranteed to exist, but
721 # if they do, we want to restore them.
722 subprocess.call(['git', 'restore', file_to_restore],
723 stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
Tony Mak0f658752019-07-19 11:11:05 +0100724
725 return True
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400726
Alan Viverette6dc45752020-04-16 14:56:20 +0000727
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000728def update_jetifier(target, build_id, beyond_corp):
729 """
730 Fetches and extracts Jetifier tool prebuilts.
731
732 Args:
733 target: Android build server target name
734 build_id: Android build server ID
735 beyond_corp: Whether to use BeyondCorp-compatible artifact fetcher
736 Return:
737 Whether the prebuilt was successfully updated.
738 """
Jeff Gaston782c3e32018-02-06 14:36:17 -0500739 repo_file = 'jetifier-standalone.zip'
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000740 repo_dir = fetch_and_extract(target, build_id.url_id, repo_file, beyond_corp)
Jeff Gaston782c3e32018-02-06 14:36:17 -0500741 if not repo_dir:
742 print_e('Failed to extract Jetifier')
743 return False
744
745 rm(jetifier_dir)
Jeff Gaston553a4372018-03-29 18:34:22 -0400746 mv(os.path.join(repo_dir, 'jetifier-standalone'), jetifier_dir)
747 os.chmod(os.path.join(jetifier_dir, 'bin', 'jetifier-standalone'), 0o755)
Jeff Gaston782c3e32018-02-06 14:36:17 -0500748 return True
749
Alan Viverette7e897e22018-03-09 15:24:10 -0500750
Alan Viverette6dc45752020-04-16 14:56:20 +0000751def update_constraint(local_file):
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000752 """
753 Extracts ConstraintLayout library prebuilts.
754
755 Args:
756 local_file: local Maven repository ZIP containing library artifacts
757 Return:
758 Whether the prebuilts were successfully updated.
759 """
Jeff Gaston9edf86c2018-04-18 13:45:23 -0400760 repo_dir = extract_artifact(local_file)
761 if not repo_dir:
Alan Viverette6dc45752020-04-16 14:56:20 +0000762 print_e('Failed to extract Constraint Layout')
Jeff Gaston9edf86c2018-04-18 13:45:23 -0400763 return False
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000764 return transform_maven_repos([repo_dir], os.path.join(extras_dir, 'constraint-layout-x'),
765 extract_res=False)
Jeff Gaston9edf86c2018-04-18 13:45:23 -0400766
Alan Viverette45837092017-05-12 14:50:53 -0400767
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000768def update_material(local_file):
769 """
770 Extracts Material Design Components library prebuilts.
771
772 Args:
773 local_file: local Maven repository ZIP containing library artifacts
774 Return:
775 Whether the prebuilts were successfully updated.
776 """
777 design_dir = extract_artifact(local_file)
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400778 if not design_dir:
Alan Viverette6dc45752020-04-16 14:56:20 +0000779 print_e('Failed to extract Material Design Components')
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400780 return False
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000781 return transform_maven_repos([design_dir], os.path.join(extras_dir, 'material-design-x'),
782 extract_res=False)
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400783
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400784
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000785def update_framework(target, build_id, sdk_dir, beyond_corp):
Anton Hansson83f92172020-03-26 11:12:03 +0000786 api_scope_list = ['public', 'system', 'test', 'module-lib', 'system-server']
Sundong Ahn66091f22018-08-29 18:54:28 +0900787 if sdk_dir == 'current':
788 api_scope_list.append('core')
789
790 for api_scope in api_scope_list:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000791 target_dir = os.path.join(sdk_dir, api_scope)
Sundong Ahn66091f22018-08-29 18:54:28 +0900792 if api_scope == 'core':
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000793 artifact_to_path = {'core.current.stubs.jar': os.path.join(target_dir, 'android.jar')}
Sundong Ahn66091f22018-08-29 18:54:28 +0900794 else:
Paul Duffin6815a312021-10-28 13:02:51 +0100795 artifact_to_path = {
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000796 'apistubs/android/' + api_scope + '/*.jar': os.path.join(target_dir, '*'),
Paul Duffin6815a312021-10-28 13:02:51 +0100797 }
798 if api_scope == 'public' or api_scope == 'module-lib':
799 # Distinct core-for-system-modules.jar files are only provided
800 # for the public and module-lib API surfaces.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000801 artifact_to_path[
802 'system-modules/' + api_scope + '/core-for-system-modules.jar'] = os.path.join(
803 target_dir, '*')
Anton Hansson1d01a032018-04-09 10:29:37 +0100804
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000805 if not fetch_artifacts(target, build_id, artifact_to_path, beyond_corp):
Anton Hansson1d01a032018-04-09 10:29:37 +0100806 return False
807
Jiyong Park1d1c9632018-05-29 17:45:27 +0900808 if api_scope == 'public':
Anton Hansson1d01a032018-04-09 10:29:37 +0100809 # Fetch a few artifacts from the public sdk.
Sundong Ahn66091f22018-08-29 18:54:28 +0900810 artifact = 'sdk-repo-linux-platforms-%s.zip' % build_id.fs_id
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000811 artifact_path = fetch_artifact(target, build_id.url_id, artifact, beyond_corp)
Anton Hansson9709fd42018-04-03 16:52:13 +0100812 if not artifact_path:
813 return False
Anton Hansson1d01a032018-04-09 10:29:37 +0100814
815 with zipfile.ZipFile(artifact_path) as zipFile:
Colin Crossd338d702020-07-10 19:17:54 -0700816 extra_files = [
817 'android.jar',
818 'framework.aidl',
819 'uiautomator.jar',
Colin Crossd338d702020-07-10 19:17:54 -0700820 'data/annotations.zip',
821 'data/api-versions.xml']
822 for filename in extra_files:
Anton Hanssona26e4812020-03-25 12:54:39 +0000823 matches = list(filter(lambda path: filename in path, zipFile.namelist()))
824 if len(matches) != 1:
825 print_e('Expected 1 file named \'%s\' in zip %s, found %d' %
826 (filename, zipFile.filename, len(matches)))
827 return False
828 zip_path = matches[0]
829 src_path = zipFile.extract(zip_path)
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000830 dst_path = os.path.join(target_dir, filename)
Anton Hanssona26e4812020-03-25 12:54:39 +0000831 mv(src_path, dst_path)
Anton Hansson9709fd42018-04-03 16:52:13 +0100832
Anton Hansson73be1512021-06-24 10:56:05 +0100833 # Filtered API DB is currently only available for "public"
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000834 fetch_artifacts(target, build_id, {'api-versions-public-filtered.xml': os.path.join(
835 target_dir, 'data/api-versions-filtered.xml')}, beyond_corp)
Anton Hansson73be1512021-06-24 10:56:05 +0100836
Alan Viverettecd3de262017-08-14 09:51:30 -0400837 return True
Alan Viverette45837092017-05-12 14:50:53 -0400838
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000839
Sundong Ahncc34cc32018-07-11 15:18:47 +0900840def update_makefile(build_id):
841 template = '"%s",\n\
842 "current"'
843 makefile = os.path.join(git_dir, 'Android.bp')
844
845 with open(makefile, 'r+') as f:
846 contents = f.read().replace('"current"', template % build_id)
847 f.seek(0)
848 f.write(contents)
849
850 return True
Alan Viverette45837092017-05-12 14:50:53 -0400851
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000852
853def finalize_sdk(target, build_id, sdk_version, beyond_corp):
Anton Hansson1d01a032018-04-09 10:29:37 +0100854 target_finalize_dir = '%d' % sdk_version
Anton Hansson9709fd42018-04-03 16:52:13 +0100855
Anton Hanssonaa554c02020-04-30 14:06:20 +0100856 for api_scope in ['public', 'system', 'test', 'module-lib', 'system-server']:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000857 artifact_to_path = {f'apistubs/android/{api_scope}/api/*.txt': os.path.join(
858 target_finalize_dir, api_scope, 'api', '*')}
Sundong Ahn66091f22018-08-29 18:54:28 +0900859
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000860 if not fetch_artifacts(target, build_id, artifact_to_path, beyond_corp):
Sundong Ahn66091f22018-08-29 18:54:28 +0900861 return False
862
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000863 return update_framework(target, build_id, target_finalize_dir, beyond_corp) and update_makefile(
864 target_finalize_dir)
Anton Hansson9709fd42018-04-03 16:52:13 +0100865
Anton Hansson9709fd42018-04-03 16:52:13 +0100866
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000867def update_framework_current(target, build_id, beyond_corp):
868 return update_framework(target, build_id, current_path, beyond_corp)
Anton Hansson9709fd42018-04-03 16:52:13 +0100869
870
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000871def update_buildtools(target, arch, build_id, beyond_corp):
Jeff Gaston13e38412018-02-06 14:45:36 -0500872 artifact_path = fetch_and_extract(target, build_id.url_id,
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000873 f'sdk-repo-{arch}-build-tools-{build_id.fs_id}.zip',
874 beyond_corp)
Alan Viverettec1c32b62017-12-20 09:40:36 -0500875 if not artifact_path:
876 return False
877
878 top_level_dir = os.listdir(artifact_path)[0]
879 src_path = os.path.join(artifact_path, top_level_dir)
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000880 dst_path = os.path.join(buildtools_dir, arch)
Colin Cross20648d32021-02-12 13:30:51 -0800881
882 # There are a few libraries that have been manually added to the
883 # build tools, copy them from the destination back to the source
884 # before the destination is overwritten.
885 files_to_save = (
886 'lib64/libconscrypt_openjdk_jni.dylib',
887 'lib64/libconscrypt_openjdk_jni.so',
888 'bin/lib64/libwinpthread-1.dll',
889 )
890 for file in files_to_save:
891 src_file = os.path.join(dst_path, file)
892 dst_file = os.path.join(src_path, file)
893 if os.path.exists(dst_path):
894 mv(src_file, dst_file)
895
Alan Viverettec1c32b62017-12-20 09:40:36 -0500896 mv(src_path, dst_path)
897
898 # Move all top-level files to /bin and make them executable
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000899 bin_path = os.path.join(dst_path, 'bin')
900 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 -0500901 for file in top_level_files:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000902 src_file = os.path.join(dst_path, file)
903 dst_file = os.path.join(bin_path, file)
Alan Viverettec1c32b62017-12-20 09:40:36 -0500904 mv(src_file, dst_file)
905 os.chmod(dst_file, 0o755)
906
Colin Cross6673ceb2021-02-12 13:14:14 -0800907 # Make the files under lld-bin executable
908 lld_bin_files = os.listdir(os.path.join(dst_path, 'lld-bin'))
909 for file in lld_bin_files:
910 os.chmod(os.path.join(dst_path, 'lld-bin', file), 0o755)
911
Alan Viverettec1c32b62017-12-20 09:40:36 -0500912 # Remove renderscript
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000913 rm(os.path.join(dst_path, 'renderscript'))
Alan Viverettec1c32b62017-12-20 09:40:36 -0500914
915 return True
916
917
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000918def has_uncommitted_changes():
Jeff Gastoncc296a82018-03-23 14:33:24 -0400919 try:
920 # Make sure we don't overwrite any pending changes.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000921 diff_command = f'cd {git_dir} && git diff --quiet'
922 subprocess.check_call(diff_command, shell=True)
923 subprocess.check_call(f'{diff_command} --cached', shell=True)
Jeff Gastoncc296a82018-03-23 14:33:24 -0400924 return False
925 except subprocess.CalledProcessError:
926 return True
927
928
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000929def main():
930 parser = argparse.ArgumentParser(
931 description='Update current prebuilts')
932 parser.add_argument(
933 'source', nargs='?',
934 help='Build server build ID or local Maven ZIP file')
935 parser.add_argument(
936 '-m', '--material', action='store_true',
937 help='If specified, updates only Material Design Components')
938 parser.add_argument(
939 '-c', '--constraint', action='store_true',
940 help='If specified, updates only Constraint Layout')
941 parser.add_argument(
942 '-j', '--jetifier', action='store_true',
943 help='If specified, updates only Jetifier')
944 parser.add_argument(
945 '-p', '--platform', action='store_true',
946 help='If specified, updates only the Android Platform')
947 parser.add_argument(
948 '-f', '--finalize_sdk', type=int,
949 help='Finalize the build as the specified SDK version. Must be used together with -e')
950 parser.add_argument(
951 '-e', '--finalize_extension', type=int,
952 help='Finalize the build as the specified extension SDK version. Must be used together with -f')
953 parser.add_argument('--bug', type=int, help='The bug number to add to the commit message.')
954 parser.add_argument(
955 '--sdk_target',
956 default=framework_sdk_target,
957 help='If specified, the name of the build target from which to retrieve the SDK when -p or -f '
958 'is specified.')
959 parser.add_argument(
960 '-b', '--buildtools', action='store_true',
961 help='If specified, updates only the Build Tools')
962 parser.add_argument(
963 '-x', '--androidx', action='store_true',
964 help='If specified, updates only the Jetpack (androidx) libraries excluding those covered by '
965 'other arguments')
966 parser.add_argument(
967 '--include', action='append', default=[],
968 help='If specified with -x, includes the specified Jetpack library Maven group or artifact for '
969 'updates. Applied before exclude.')
970 parser.add_argument(
971 '--exclude', action='append', default=[],
972 help='If specified with -x, excludes the specified Jetpack library Maven group or artifact '
973 'from updates')
974 parser.add_argument(
975 '-g', '--gmaven', action='store_true',
976 help='If specified, updates only the artifact from GMaven libraries excluding those covered by '
977 'other arguments')
978 parser.add_argument(
979 '--commit-first', action='store_true',
980 help='If specified, then if uncommited changes exist, commit before continuing')
981 parser.add_argument(
982 '--beyond-corp', action='store_true',
983 help='If specified, then fetch artifacts with tooling that works on BeyondCorp devices')
Anton Hansson4bcebac2022-04-07 17:23:18 +0100984
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000985 rm(temp_dir)
Alan Viveretted4527e62017-05-11 15:03:25 -0400986
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000987 args = parser.parse_args()
Jeff Gastoncc296a82018-03-23 14:33:24 -0400988
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000989 # Validate combinations of arguments.
990 if not args.source and (args.platform or args.buildtools or args.jetifier
991 or args.androidx or args.material or args.finalize_sdk
992 or args.constraint):
993 parser.error('You must specify a build ID or local Maven ZIP file')
994 sys.exit(1)
995 if not (args.gmaven or args.platform or args.buildtools or args.jetifier
996 or args.androidx or args.material or args.finalize_sdk
997 or args.finalize_extension or args.constraint):
998 parser.error('You must specify at least one target to update')
999 sys.exit(1)
1000 if (args.finalize_sdk is None) != (args.finalize_extension is None):
1001 parser.error('Either both or neither of -e and -f must be specified.')
1002 sys.exit(1)
1003 if args.finalize_sdk and not args.bug:
1004 parser.error('Specifying a bug ID with --bug is required when finalizing an SDK.')
1005 sys.exit(1)
Alan Viveretted4527e62017-05-11 15:03:25 -04001006
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001007 # Validate the build environment for POM-dependent targets.
1008 if (args.constraint or args.material or args.androidx or args.gmaven) \
1009 and which('pom2bp') is None:
1010 parser.error('Cannot find pom2bp in path; please run lunch to set up build environment. '
1011 'You may also need to run \'m pom2bp\' if it hasn\'t been built already.')
1012 sys.exit(1)
Anton Hansson57a1b142022-04-07 17:27:41 +01001013
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001014 # Validate the git status.
1015 if has_uncommitted_changes():
1016 if args.commit_first:
1017 subprocess.check_call(f'cd {git_dir} && git add -u', shell=True)
1018 subprocess.check_call(f'cd {git_dir} && git commit -m \'save working state\'',
1019 shell=True)
1020 if has_uncommitted_changes():
1021 self_file = os.path.basename(__file__)
1022 print_e(f'FAIL: There are uncommitted changes here. Please commit or stash before '
1023 f'continuing, because {self_file} will run "git reset --hard" if execution fails')
1024 sys.exit(1)
Anton Hansson4bcebac2022-04-07 17:23:18 +01001025
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001026 if args.bug:
1027 commit_msg_suffix = '\n\nBug: {args.bug}'
Alan Viverette129555e2018-01-30 09:57:57 -05001028 else:
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001029 commit_msg_suffix = ''
Alan Viveretted4527e62017-05-11 15:03:25 -04001030
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001031 # Are we fetching a build ID or using a local file?
1032 build_id = None
1033 file = None
1034 if args.source:
1035 build_id = parse_build_id(args.source)
1036 if build_id is None:
1037 file = args.source
1038
Alan Viveretted4527e62017-05-11 15:03:25 -04001039 try:
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001040 components = []
1041 if args.constraint:
1042 if update_constraint(file):
1043 components.append('Constraint Layout')
1044 else:
1045 print_e('Failed to update Constraint Layout, aborting...')
1046 sys.exit(1)
1047 if args.material:
1048 if update_material(file):
1049 components.append('Material Design Components')
1050 else:
1051 print_e('Failed to update Material Design Components, aborting...')
1052 sys.exit(1)
1053 if args.gmaven:
1054 updated_artifacts = update_gmaven(gmaven_artifacts)
1055 if updated_artifacts:
1056 components.append('\n'.join(updated_artifacts))
1057 else:
1058 print_e('Failed to update GMaven, aborting...')
1059 sys.exit(1)
1060 if args.androidx:
1061 if update_androidx('androidx', build_id, file, args.include, args.exclude,
1062 args.beyond_corp):
1063 components.append('AndroidX')
1064 else:
1065 print_e('Failed to update AndroidX, aborting...')
1066 sys.exit(1)
1067 if args.jetifier:
1068 if update_jetifier('androidx', build_id, args.beyond_corp):
1069 components.append('Jetifier')
1070 else:
1071 print_e('Failed to update Jetifier, aborting...')
1072 sys.exit(1)
1073 if args.platform or args.finalize_sdk:
1074 if update_framework_current(args.sdk_target, build_id, args.beyond_corp):
1075 components.append('platform SDK')
1076 else:
1077 print_e('Failed to update platform SDK, aborting...')
1078 sys.exit(1)
1079 if args.finalize_sdk:
1080 n = args.finalize_sdk
1081 if not finalize_sdk(args.sdk_target, build_id, n, args.beyond_corp):
1082 print_e('Failed to finalize SDK %d, aborting...' % n)
1083 sys.exit(1)
1084
1085 # We commit the finalized dir separately from the current sdk update.
1086 msg = f'Import final sdk version {n} from build {build_id.url_id}{commit_msg_suffix}'
1087 subprocess.check_call(['git', 'add', '%d' % n])
1088 subprocess.check_call(['git', 'add', 'Android.bp'])
1089 subprocess.check_call(['git', 'commit', '-m', msg])
1090
1091 # Finalize extension sdk level
1092 readme = (f'- {args.finalize_extension}: Finalized together with '
1093 'Android {args.finalize_sdk} (all modules)')
1094 cmd = extension_sdk_finalization_cmd.format(
1095 readme=readme,
1096 bug=args.bug,
1097 extension_version=args.finalize_extension,
1098 build_id=build_id.url_id)
1099 subprocess.check_call(shlex.split(cmd), cwd=repo_root_dir.resolve())
1100 if args.buildtools:
1101 if update_buildtools('sdk_mac', 'darwin', build_id, args.beyond_corp) \
1102 and update_buildtools('sdk', 'linux', build_id, args.beyond_corp) \
1103 and update_buildtools('sdk', 'windows', build_id, args.beyond_corp):
1104 components.append('build tools')
1105 else:
1106 print_e('Failed to update build tools, aborting...')
1107 sys.exit(1)
1108
1109 # Build the git commit.
1110 subprocess.check_call(['git', 'add', current_path, buildtools_dir])
1111
1112 # Build the commit message.
1113 components_msg = ', '.join(components)
1114 argv_msg = ' '.join(sys.argv)
1115 if not args.source and args.gmaven:
1116 src_msg = 'GMaven'
1117 elif not args.source.isnumeric():
1118 src_msg = 'local Maven ZIP'
1119 else:
1120 src_msg = f'build {build_id.url_id}'
1121 msg = f'Import {components_msg} from {src_msg}\n\n{argv_msg}{commit_msg_suffix}'
1122
1123 # Create the git commit.
1124 subprocess.check_call(['git', 'commit', '-q', '-m', msg])
1125
1126 if args.finalize_sdk:
1127 print('NOTE: Created three commits:')
1128 subprocess.check_call(['git', 'log', '-3', '--oneline'])
1129 else:
1130 print('Created commit:')
1131 subprocess.check_call(['git', 'log', '-1', '--oneline'])
1132 print('Remember to test this change before uploading it to Gerrit!')
1133
1134 finally:
1135 # Revert all stray files, including the downloaded zip.
1136 try:
1137 with open(os.devnull, 'w') as bitbucket:
1138 subprocess.check_call(['git', 'add', '-Af', '.'], stdout=bitbucket)
1139 subprocess.check_call(
1140 ['git', 'commit', '-m', 'COMMIT TO REVERT - RESET ME!!!', '--allow-empty'],
1141 stdout=bitbucket)
1142 subprocess.check_call(['git', 'reset', '--hard', 'HEAD~1'], stdout=bitbucket)
1143 except subprocess.CalledProcessError:
1144 print_e('ERROR: Failed cleaning up, manual cleanup required!!!')
1145
1146
1147# Add automatic entries to maven_to_make.
1148populate_maven_to_make(maven_to_make)
1149
1150if __name__ == '__main__':
1151 main()