blob: 6a95dcc95cc757a7fd3e328d91bcc783392974bf [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': {},
93 'androidx.core:core-ktx': {},
94 'androidx.core.uwb:uwb': {},
95 'androidx.core.uwb:uwb-rxjava3': {},
96 'androidx.contentpaging:contentpaging': {},
97 'androidx.coordinatorlayout:coordinatorlayout': {},
98 'androidx.legacy:legacy-support-core-ui': {},
99 'androidx.legacy:legacy-support-core-utils': {},
100 'androidx.cursoradapter:cursoradapter': {},
101 'androidx.browser:browser': {},
102 'androidx.customview:customview': {},
103 'androidx.customview:customview-poolingcontainer': {},
104 'androidx.documentfile:documentfile': {},
105 'androidx.drawerlayout:drawerlayout': {},
106 'androidx.dynamicanimation:dynamicanimation': {},
107 'androidx.emoji:emoji': {},
108 'androidx.emoji:emoji-appcompat': {},
109 'androidx.emoji:emoji-bundled': {},
110 'androidx.emoji2:emoji2': {},
111 'androidx.emoji2:emoji2-views-helper': {},
112 'androidx.exifinterface:exifinterface': {},
113 'androidx.fragment:fragment': {},
114 'androidx.fragment:fragment-ktx': {},
115 'androidx.heifwriter:heifwriter': {},
116 'androidx.interpolator:interpolator': {},
117 'androidx.loader:loader': {},
118 'androidx.media:media': {},
119 'androidx.media2:media2-player': {},
120 'androidx.media2:media2-session': {},
121 'androidx.media2:media2-common': {},
122 'androidx.media2:media2-exoplayer': {},
123 'androidx.media2:media2-widget': {},
124 'androidx.navigation:navigation-common': {},
125 'androidx.navigation:navigation-common-ktx': {},
126 'androidx.navigation:navigation-fragment': {},
127 'androidx.navigation:navigation-fragment-ktx': {},
128 'androidx.navigation:navigation-runtime': {},
129 'androidx.navigation:navigation-runtime-ktx': {},
130 'androidx.navigation:navigation-ui': {},
131 'androidx.navigation:navigation-ui-ktx': {},
132 'androidx.percentlayout:percentlayout': {},
133 'androidx.print:print': {},
134 'androidx.recommendation:recommendation': {},
135 'androidx.recyclerview:recyclerview-selection': {},
136 'androidx.savedstate:savedstate': {},
137 'androidx.savedstate:savedstate-ktx': {},
138 'androidx.slidingpanelayout:slidingpanelayout': {},
139 'androidx.swiperefreshlayout:swiperefreshlayout': {},
140 'androidx.textclassifier:textclassifier': {},
141 'androidx.transition:transition': {},
142 'androidx.tvprovider:tvprovider': {},
143 'androidx.legacy:legacy-support-v13': {},
144 'androidx.legacy:legacy-preference-v14': {},
145 'androidx.leanback:leanback': {},
146 'androidx.leanback:leanback-grid': {},
147 'androidx.leanback:leanback-preference': {},
148 'androidx.legacy:legacy-support-v4': {},
149 'androidx.appcompat:appcompat': {},
150 'androidx.appcompat:appcompat-resources': {},
151 'androidx.cardview:cardview': {},
152 'androidx.gridlayout:gridlayout': {},
153 'androidx.mediarouter:mediarouter': {},
154 'androidx.palette:palette': {},
155 'androidx.preference:preference': {},
156 'androidx.recyclerview:recyclerview': {},
157 'androidx.vectordrawable:vectordrawable': {},
158 'androidx.viewpager:viewpager': {},
159 'androidx.viewpager2:viewpager2': {},
160 'androidx.wear:wear': {},
161 'androidx.wear:wear-ongoing': {},
162 'androidx.javascriptengine:javascriptengine': {},
163 'androidx.webkit:webkit': {},
164 'androidx.biometric:biometric': {},
165 'androidx.autofill:autofill': {},
166 'androidx.appsearch:appsearch': {},
167 'androidx.appsearch:appsearch-builtin-types': {},
168 'androidx.appsearch:appsearch-compiler': {
169 'name': 'androidx.appsearch_appsearch-compiler',
170 'host': True
171 },
172 'androidx.appsearch:appsearch-local-storage': {
173 'name': 'androidx.appsearch_appsearch_local_storage'
174 },
175 'androidx.appsearch:appsearch-platform-storage': {},
176 'androidx.car.app:app': {},
177 'androidx.car.app:app-automotive': {},
178 'androidx.car.app:app-testing': {},
179 'androidx.startup:startup-runtime': {},
180 'androidx.window:window': {
181 'optional-uses-libs': {
182 'androidx.window.extensions',
183 'androidx.window.sidecar'
184 }
185 },
186 'androidx.resourceinspection:resourceinspection-annotation': {},
187 'androidx.profileinstaller:profileinstaller': {},
188 'androidx.test.uiautomator:uiautomator': {},
Aurimas Liutikas6e87bbf2021-07-30 10:04:05 -0700189
Alan Viverettef44e2f92021-08-31 17:26:26 +0000190 # AndroidX for Compose
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000191 'androidx.compose.compiler:compiler-hosted': {
192 'host': True
193 },
194 'androidx.compose.runtime:runtime': {},
195 'androidx.compose.runtime:runtime-saveable': {},
196 'androidx.compose.runtime:runtime-livedata': {},
197 'androidx.compose.foundation:foundation': {},
198 'androidx.compose.foundation:foundation-layout': {},
199 'androidx.compose.foundation:foundation-text': {},
200 'androidx.compose.ui:ui': {},
201 'androidx.compose.ui:ui-geometry': {},
202 'androidx.compose.ui:ui-graphics': {},
203 'androidx.compose.ui:ui-text': {},
204 'androidx.compose.ui:ui-tooling': {},
205 'androidx.compose.ui:ui-tooling-preview': {},
206 'androidx.compose.ui:ui-tooling-data': {},
207 'androidx.compose.ui:ui-unit': {},
208 'androidx.compose.ui:ui-util': {},
Jordan Demeulenaere606dca92022-07-29 16:09:28 +0200209 'androidx.compose.ui:ui-test': { },
210 'androidx.compose.ui:ui-test-junit4': { },
Jordan Demeulenaere76170242022-05-16 12:18:39 +0200211 'androidx.compose.ui:ui-test-manifest': { },
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000212 'androidx.compose.animation:animation-core': {},
213 'androidx.compose.animation:animation': {},
214 'androidx.compose.material:material-icons-core': {},
Jordan Demeulenaere606dca92022-07-29 16:09:28 +0200215 'androidx.compose.material:material-icons-extended': { },
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000216 'androidx.compose.material:material-ripple': {},
217 'androidx.compose.material:material': {},
218 'androidx.compose.material3:material3': {},
219 'androidx.activity:activity-compose': {},
Jordan Demeulenaere606dca92022-07-29 16:09:28 +0200220 'androidx.navigation:navigation-compose': { },
221 'androidx.lifecycle:lifecycle-viewmodel-compose': { },
Alan Viverettef44e2f92021-08-31 17:26:26 +0000222
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400223 # AndroidX for Multidex
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000224 'androidx.multidex:multidex': {},
225 'androidx.multidex:multidex-instrumentation': {},
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400226
227 # AndroidX for Constraint Layout
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000228 'androidx.constraintlayout:constraintlayout': {
229 'name': 'androidx-constraintlayout_constraintlayout'
230 },
231 'androidx.constraintlayout:constraintlayout-solver': {
232 'name': 'androidx-constraintlayout_constraintlayout-solver'
233 },
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400234
235 # AndroidX for Architecture Components
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000236 'androidx.arch.core:core-common': {},
237 'androidx.arch.core:core-runtime': {},
238 'androidx.lifecycle:lifecycle-common': {},
239 'androidx.lifecycle:lifecycle-common-java8': {},
240 'androidx.lifecycle:lifecycle-extensions': {},
241 'androidx.lifecycle:lifecycle-livedata': {},
242 'androidx.lifecycle:lifecycle-livedata-ktx': {},
243 'androidx.lifecycle:lifecycle-livedata-core': {},
244 'androidx.lifecycle:lifecycle-livedata-core-ktx': {},
245 'androidx.lifecycle:lifecycle-process': {},
246 'androidx.lifecycle:lifecycle-runtime': {},
247 'androidx.lifecycle:lifecycle-runtime-ktx': {},
248 'androidx.lifecycle:lifecycle-service': {},
249 'androidx.lifecycle:lifecycle-viewmodel': {},
250 'androidx.lifecycle:lifecycle-viewmodel-ktx': {},
251 'androidx.lifecycle:lifecycle-viewmodel-savedstate': {},
252 'androidx.paging:paging-common': {},
253 'androidx.paging:paging-common-ktx': {},
254 'androidx.paging:paging-runtime': {},
255 'androidx.sqlite:sqlite': {},
256 'androidx.sqlite:sqlite-framework': {},
257 'androidx.room:room-common': {
258 'host_and_device': True
259 },
260 'androidx.room:room-compiler': {
261 'host': True,
262 'extra-static-libs': {
Krzysztof Kosiński2450c552022-11-04 21:35:51 +0000263 'guava'
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000264 }
265 },
266 'androidx.room:room-migration': {
267 'host_and_device': True
268 },
269 'androidx.room:room-runtime': {},
270 'androidx.room:room-testing': {},
271 'androidx.room:room-compiler-processing': {
272 'host': True
273 },
274 'androidx.work:work-runtime': {},
275 'androidx.work:work-runtime-ktx': {},
276 'androidx.work:work-testing': {},
Allenab72f012018-01-29 18:10:23 -0800277
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400278 # Third-party dependencies
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000279 'com.google.android:flexbox': {
280 'name': 'flexbox',
281 'path': 'flexbox'
282 },
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400283
Jeff Gastonfa7c7e82018-04-06 13:35:48 -0400284 # Androidx Material Design Components
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000285 'com.google.android.material:material': {},
Alan Viverette95f6d362017-04-06 09:40:50 -0400286}
287
Alan Viverettecdfc9892021-08-31 19:35:58 +0000288# Mapping of POM dependencies to Soong build targets
289deps_rewrite = {
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000290 'auto-common': 'auto_common',
291 'auto-value-annotations': 'auto_value_annotations',
292 'com.google.auto.value:auto-value': 'libauto_value_plugin',
293 'monitor': 'androidx.test.monitor',
294 'rules': 'androidx.test.rules',
295 'runner': 'androidx.test.runner',
296 'androidx.test:core': 'androidx.test.core',
297 'com.squareup:javapoet': 'javapoet',
298 'com.google.guava:listenablefuture': 'guava-listenablefuture-prebuilt-jar',
299 'sqlite-jdbc': 'xerial-sqlite-jdbc',
300 'com.intellij:annotations': 'jetbrains-annotations',
301 'javax.annotation:javax.annotation-api': 'javax-annotation-api-prebuilt-host-jar',
302 'org.robolectric:robolectric': 'Robolectric_all-target',
303 'org.jetbrains.kotlin:kotlin-stdlib-common': 'kotlin-stdlib',
304 'org.jetbrains.kotlinx:kotlinx-coroutines-core': 'kotlinx_coroutines',
305 'org.jetbrains.kotlinx:kotlinx-coroutines-android': 'kotlinx_coroutines_android',
Jordan Demeulenaere606dca92022-07-29 16:09:28 +0200306 'org.jetbrains.kotlinx:kotlinx-coroutines-test':'kotlinx_coroutines_test',
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000307 'org.jetbrains.kotlinx:kotlinx-metadata-jvm': 'kotlinx_metadata_jvm',
Jordan Demeulenaere606dca92022-07-29 16:09:28 +0200308 'androidx.test.espresso:espresso-core':'androidx.test.espresso.core',
309 'androidx.test.espresso:espresso-idling-resource':'androidx.test.espresso.idling-resource',
Alan Viverettecdfc9892021-08-31 19:35:58 +0000310}
311
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000312# List of artifacts that will be updated from GMaven
313# Use pattern: `group:library:version:extension`
314# e.g.:
315# androidx.appcompat:appcompat:1.2.0:aar
316# Use `latest` to always fetch the latest version.
317# e.g.:
318# androidx.appcompat:appcompat:latest:aar
319# Also make sure you add `group:library`:{} to maven_to_make as well.
320gmaven_artifacts = {}
Alan Viverettef3c12722021-08-30 19:50:33 +0000321
Alan Viverette95f6d362017-04-06 09:40:50 -0400322# Always remove these files.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000323denylist_files = [
Alan Viverette95f6d362017-04-06 09:40:50 -0400324 'annotations.zip',
325 'public.txt',
326 'R.txt',
Alan Viverette44ad4e42017-08-09 17:45:00 -0400327 'AndroidManifest.xml',
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000328 os.path.join('libs', 'noto-emoji-compat-java.jar')
Alan Viverette95f6d362017-04-06 09:40:50 -0400329]
330
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000331artifact_pattern = re.compile(r'^(.+?)-(\d+\.\d+\.\d+(?:-\w+\d+)?(?:-[\d.]+)*)\.(jar|aar)$')
Alan Viverette95f6d362017-04-06 09:40:50 -0400332
Alan Viverettec960cfb2017-12-04 13:09:22 -0500333
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000334def name_for_artifact(group_artifact):
335 """Returns the build system target name for a given library's Maven coordinate.
336
337 Args:
338 group_artifact: an unversioned Maven artifact coordinate, ex. androidx.core:core
339 Returns:
340 The build system target name for the artifact, ex. androidx.core_core.
341 """
342 return group_artifact.replace(':', '_')
Alan Viverettec960cfb2017-12-04 13:09:22 -0500343
344
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000345def path_for_artifact(group_artifact):
346 """Returns the file system path for a given library's Maven coordinate.
347
348 Args:
349 group_artifact: an unversioned Maven artifact coordinate, ex. androidx.core:core
350 Returns:
351 The file system path for the artifact, ex. androidx/core/core.
352 """
353 return group_artifact.replace('.', '/').replace(':', '/')
Alan Viverettef5cb0e62017-11-17 15:15:23 -0500354
Alan Viverette95f6d362017-04-06 09:40:50 -0400355
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000356def populate_maven_to_make(mapping):
357 """Modifies the input mapping by expanding Maven coordinate keys into build target names and
358 paths.
Alan Viverette95f6d362017-04-06 09:40:50 -0400359
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000360 Args:
361 mapping: a map where the keys are Maven coordinates
362 """
363 for key in mapping:
364 if 'name' not in mapping[key]:
365 mapping[key]['name'] = name_for_artifact(key)
366 if 'path' not in maven_to_make[key]:
367 mapping[key]['path'] = path_for_artifact(key)
Alan Viverette45837092017-05-12 14:50:53 -0400368
369
Jeff Gastonc302bb92018-03-23 13:53:48 -0400370def detect_artifacts(maven_repo_dirs):
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000371 """Parses Maven libraries from the specified directories.
372
373 Args:
374 maven_repo_dirs: a list of maven repository roots
375 Returns:
376 A map of Maven coordinate keys to MavenLibraryInfo objects parsed from POM files.
377 """
Alan Viveretted4527e62017-05-11 15:03:25 -0400378 maven_lib_info = {}
379
Dan Willemsen814152e2017-11-06 13:22:11 -0800380 # Find the latest revision for each artifact, remove others
Jeff Gastonc302bb92018-03-23 13:53:48 -0400381 for repo_dir in maven_repo_dirs:
Dan Willemsen814152e2017-11-06 13:22:11 -0800382 for root, dirs, files in os.walk(repo_dir):
383 for file in files:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000384 if file[-4:] == '.pom':
Alan Viverettec960cfb2017-12-04 13:09:22 -0500385 # Read the POM (hack hack hack).
386 group_id = ''
387 artifact_id = ''
388 version = ''
389 file = os.path.join(root, file)
390 with open(file) as pom_file:
391 for line in pom_file:
392 if line[:11] == ' <groupId>':
393 group_id = line[11:-11]
394 elif line[:14] == ' <artifactId>':
395 artifact_id = line[14:-14]
396 elif line[:11] == ' <version>':
397 version = line[11:-11]
398 if group_id == '' or artifact_id == '' or version == '':
399 print_e('Failed to find Maven artifact data in ' + file)
400 continue
Alan Viverette95f6d362017-04-06 09:40:50 -0400401
Alan Viverettec960cfb2017-12-04 13:09:22 -0500402 # Locate the artifact.
403 artifact_file = file[:-4]
404 if os.path.exists(artifact_file + '.jar'):
405 artifact_file = artifact_file + '.jar'
406 elif os.path.exists(artifact_file + '.aar'):
407 artifact_file = artifact_file + '.aar'
408 else:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000409 # This error only occurs for a handful of gradle.plugin artifacts that only
410 # ship POM files, so we probably don't need to log unless we're debugging.
411 # print_e('Failed to find artifact for ' + artifact_file)
Alan Viverettec960cfb2017-12-04 13:09:22 -0500412 continue
413
414 # Make relative to root.
415 artifact_file = artifact_file[len(root) + 1:]
416
417 # Find the mapping.
418 group_artifact = group_id + ':' + artifact_id
Jeff Gaston3e622ba2018-03-26 23:24:46 -0400419 if group_artifact in maven_to_make:
Alan Viverettec960cfb2017-12-04 13:09:22 -0500420 key = group_artifact
Jeff Gaston3e622ba2018-03-26 23:24:46 -0400421 elif artifact_id in maven_to_make:
422 key = artifact_id
Alan Viverettec960cfb2017-12-04 13:09:22 -0500423 else:
Alan Viverettecdfc9892021-08-31 19:35:58 +0000424 # No mapping entry, skip this library.
Alan Viverettec960cfb2017-12-04 13:09:22 -0500425 continue
426
427 # Store the latest version.
428 version = LooseVersion(version)
429 if key not in maven_lib_info \
430 or version > maven_lib_info[key].version:
431 maven_lib_info[key] = MavenLibraryInfo(key, group_id, artifact_id, version,
432 root, repo_dir, artifact_file)
Alan Viverette95f6d362017-04-06 09:40:50 -0400433
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400434 return maven_lib_info
435
436
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000437def transform_maven_repos(maven_repo_dirs, transformed_dir, extract_res=True,
438 include_static_deps=True, include=None, exclude=None, prepend=None):
439 """Transforms a standard Maven repository to be compatible with the Android build system.
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400440
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000441 When using the include argument by itself, all other libraries will be excluded. When using the
442 exclude argument by itself, all other libraries will be included. When using both arguments, the
443 inclusion list will be applied followed by the exclusion list.
444
445 Args:
446 maven_repo_dirs: path to local Maven repository
447 transformed_dir: relative path for output, ex. androidx
448 extract_res: whether to extract Android resources like AndroidManifest.xml from AARs
449 include_static_deps: whether to pass --static-deps to pom2bp
450 include: list of Maven groupIds or unversioned artifact coordinates to include for
451 updates, ex. androidx.core or androidx.core:core
452 exclude: list of Maven groupIds or unversioned artifact coordinates to exclude from
453 updates, ex. androidx.core or androidx.core:core
454 prepend: Path to a file containing text to be inserted at the beginning of the generated
455 build file
456 Returns:
457 True if successful, false otherwise.
458 """
459 if exclude is None:
460 exclude = []
461 if include is None:
462 include = []
463
464 cwd = os.getcwd()
465 local_repo = os.path.join(cwd, transformed_dir)
Jeff Gastona68a8d42018-03-23 14:00:13 -0400466 working_dir = temp_dir
Alan Viverette3e57a4a2017-08-11 15:49:47 -0400467
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000468 # Handle inclusions by stashing the remote artifacts for the inclusions, replacing the entire
469 # remote repo with the local repo, then restoring the stashed artifacts.
470 for remote_repo in maven_repo_dirs:
471 remote_repo = os.path.join(cwd, remote_repo)
472 paths_to_copy = []
473 for group_artifact in include:
474 artifact_path = os.path.join('m2repository', path_for_artifact(group_artifact))
475 remote_path = os.path.join(remote_repo, artifact_path)
476 working_path = os.path.join(working_dir, artifact_path)
477 if os.path.exists(remote_path):
478 print(f'Included {group_artifact} in update')
479 paths_to_copy.append([remote_path, working_path])
480
481 # Move included artifacts from repo to temp.
482 for [remote_path, working_path] in paths_to_copy:
483 mv(remote_path, working_path)
484
485 # Replace all remaining artifacts in remote repo with local repo.
486 cp(local_repo, remote_repo)
487
488 # Restore included artifacts to remote repo.
489 for [remote_path, working_path] in paths_to_copy:
490 mv(working_path, remote_path)
491
492 # Handle exclusions by replacing the remote artifacts for the exclusions with local artifacts.
493 # This must happen before we parse the artifacts.
494 for remote_repo in maven_repo_dirs:
495 for group_artifact in exclude:
496 artifact_path = os.path.join('m2repository', path_for_artifact(group_artifact))
497 remote_path = os.path.join(remote_repo, artifact_path)
498 if os.path.exists(remote_path):
499 rm(remote_path)
500 local_path = os.path.join(local_repo, artifact_path)
501 if os.path.exists(local_path):
502 print(f'Excluded {group_artifact} from update, used local artifact')
503 mv(local_path, remote_path)
504 else:
505 print(f'Excluded {group_artifact} from update, no local artifact present')
506
507 # Parse artifacts.
508 maven_lib_info = detect_artifacts(maven_repo_dirs)
509
Alan Viverettec960cfb2017-12-04 13:09:22 -0500510 if not maven_lib_info:
511 print_e('Failed to detect artifacts')
512 return False
513
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000514 # Move libraries into the working directory, performing any necessary transformations.
Alan Viveretted4527e62017-05-11 15:03:25 -0400515 for info in maven_lib_info.values():
Alan Viveretted8ce7222017-12-11 17:24:43 -0500516 transform_maven_lib(working_dir, info, extract_res)
Dan Willemsen814152e2017-11-06 13:22:11 -0800517
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000518 # Generate a single Android.bp that specifies to use all of the above artifacts.
Colin Cross74683bc2018-04-11 17:36:18 -0700519 makefile = os.path.join(working_dir, 'Android.bp')
Alan Viverette4ec9a172018-02-20 16:19:31 -0500520 with open(makefile, 'w') as f:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000521 args = ['pom2bp']
522 args.extend(['-sdk-version', '31'])
523 args.extend(['-default-min-sdk-version', '24'])
Jeff Gaston1cc06092018-03-28 15:51:02 -0400524 if include_static_deps:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000525 args.append('-static-deps')
526 if prepend:
527 args.append(f'-prepend={prepend}')
528 rewrite_names = sorted(maven_to_make.keys())
529 args.extend([f'-rewrite=^{name}$={maven_to_make[name]["name"]}' for name in rewrite_names])
530 args.extend([f'-rewrite=^{key}$={value}' for key, value in deps_rewrite.items()])
531 args.extend(["-extra-static-libs=" + maven_to_make[name]['name'] + "=" + ",".join(
532 sorted(maven_to_make[name]['extra-static-libs'])) for name in maven_to_make if
533 'extra-static-libs' in maven_to_make[name]])
534 args.extend(["-optional-uses-libs=" + maven_to_make[name]['name'] + "=" + ",".join(
535 sorted(maven_to_make[name]['optional-uses-libs'])) for name in maven_to_make if
536 'optional-uses-libs' in maven_to_make[name]])
537 args.extend([f'-host={name}' for name in maven_to_make
538 if maven_to_make[name].get('host')])
539 args.extend([f'-host-and-device={name}' for name in maven_to_make
540 if maven_to_make[name].get('host_and_device')])
541 args.extend(['.'])
Dan Willemsen814152e2017-11-06 13:22:11 -0800542 subprocess.check_call(args, stdout=f, cwd=working_dir)
Alan Viverette95f6d362017-04-06 09:40:50 -0400543
544 # Replace the old directory.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000545 local_repo = os.path.join(cwd, transformed_dir)
546 mv(working_dir, local_repo)
Alan Viverettec960cfb2017-12-04 13:09:22 -0500547 return True
Alan Viverette95f6d362017-04-06 09:40:50 -0400548
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000549
Alan Viveretted8ce7222017-12-11 17:24:43 -0500550def transform_maven_lib(working_dir, artifact_info, extract_res):
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000551 """Transforms the specified artifact for use in the Android build system.
552
553 Moves relevant files for the artifact represented by artifact_info of type MavenLibraryInfo into
554 the appropriate path inside working_dir, unpacking files needed by the build system from AARs.
555
556 Args:
557 working_dir: The directory into which the artifact should be moved
558 artifact_info: A MavenLibraryInfo representing the library artifact
559 extract_res: True to extract resources from AARs, false otherwise.
560 """
Dan Willemsen814152e2017-11-06 13:22:11 -0800561 # Move library into working dir
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000562 new_dir = os.path.normpath(
563 os.path.join(working_dir, os.path.relpath(artifact_info.dir, artifact_info.repo_dir)))
Jeff Gastonc302bb92018-03-23 13:53:48 -0400564 mv(artifact_info.dir, new_dir)
Dan Willemsen814152e2017-11-06 13:22:11 -0800565
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000566 maven_lib_type = os.path.splitext(artifact_info.file)[1][1:]
Alan Viveretted4527e62017-05-11 15:03:25 -0400567
Alan Viverettef3c12722021-08-30 19:50:33 +0000568 group_artifact = artifact_info.key
569 make_lib_name = maven_to_make[group_artifact]['name']
570 make_dir_name = maven_to_make[group_artifact]['path']
Alan Viveretted4527e62017-05-11 15:03:25 -0400571
Alan Viverette129555e2018-01-30 09:57:57 -0500572 artifact_file = os.path.join(new_dir, artifact_info.file)
573
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000574 if maven_lib_type == 'aar':
Colin Cross59b59db2018-04-24 13:58:05 -0700575 if extract_res:
576 target_dir = os.path.join(working_dir, make_dir_name)
577 if not os.path.exists(target_dir):
578 os.makedirs(target_dir)
Dan Willemsen814152e2017-11-06 13:22:11 -0800579
Alan Viverettec960cfb2017-12-04 13:09:22 -0500580 process_aar(artifact_file, target_dir)
Alan Viveretted4527e62017-05-11 15:03:25 -0400581
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000582 with zipfile.ZipFile(artifact_file) as zip_file:
583 manifests_dir = os.path.join(working_dir, 'manifests')
584 zip_file.extract('AndroidManifest.xml', os.path.join(manifests_dir, make_lib_name))
Alan Viveretted4527e62017-05-11 15:03:25 -0400585
Alan Viverette95f6d362017-04-06 09:40:50 -0400586
Alan Viverettec960cfb2017-12-04 13:09:22 -0500587def process_aar(artifact_file, target_dir):
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000588 """Extracts and cleans up the contents of an AAR file to the specified directory.
589
590 Removes classes.jar, empty directories, and denylisted files.
591
592 Args:
593 artifact_file: path to the AAR to extract
594 target_dir: directory into which the contents should be extracted
595 """
Alan Viverette95f6d362017-04-06 09:40:50 -0400596 # Extract AAR file to target_dir.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000597 with zipfile.ZipFile(artifact_file) as zip_file:
598 zip_file.extractall(target_dir)
Alan Viverette95f6d362017-04-06 09:40:50 -0400599
Dan Willemsen814152e2017-11-06 13:22:11 -0800600 # Remove classes.jar
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000601 classes_jar = os.path.join(target_dir, 'classes.jar')
Alan Viverette95f6d362017-04-06 09:40:50 -0400602 if os.path.exists(classes_jar):
Dan Willemsen814152e2017-11-06 13:22:11 -0800603 os.remove(classes_jar)
Alan Viverette95f6d362017-04-06 09:40:50 -0400604
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000605 # Remove empty dirs.
606 for root, dirs, files in os.walk(target_dir, topdown=False):
607 for dir_name in dirs:
608 dir_path = os.path.join(root, dir_name)
Alan Viverette95f6d362017-04-06 09:40:50 -0400609 if not os.listdir(dir_path):
610 os.rmdir(dir_path)
611
612 # Remove top-level cruft.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000613 for file in denylist_files:
Alan Viverette95f6d362017-04-06 09:40:50 -0400614 file_path = os.path.join(target_dir, file)
615 if os.path.exists(file_path):
616 os.remove(file_path)
617
Alan Viverettef17c9402017-07-19 12:57:40 -0400618
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000619def fetch_gmaven_artifact(artifact):
620 """Fetch a GMaven artifact.
621
622 Downloads a GMaven artifact
623 (https://developer.android.com/studio/build/dependencies#gmaven-access)
624
625 Args:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000626 artifact: an instance of GMavenArtifact.
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000627 """
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000628 pom_path = maven_path_for_artifact(
629 'gmaven', artifact.group, artifact.library, artifact.version, 'pom')
630 artifact_path = maven_path_for_artifact(
631 'gmaven', artifact.group, artifact.library, artifact.version, artifact.ext)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000632
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000633 download_file_to_disk(artifact.get_pom_file_url(), pom_path)
634 download_file_to_disk(artifact.get_artifact_url(), artifact_path)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000635
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000636 return os.path.dirname(artifact_path)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000637
638
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000639def download_file_to_disk(url, filepath):
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000640 """Download the file at URL to the location dictated by the path.
641
642 Args:
643 url: Remote URL to download file from.
644 filepath: Filesystem path to write the file to.
645 """
646 print(f'Downloading URL: {url}')
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000647 file_data = request.urlopen(url)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000648
649 try:
650 os.makedirs(os.path.dirname(filepath))
651 except os.error:
652 # This is a common situation - os.makedirs fails if dir already exists.
653 pass
654 try:
655 with open(filepath, 'wb') as f:
656 f.write(six.ensure_binary(file_data.read()))
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000657 except Exception as e:
658 print_e(e.__class__, 'occurred while reading', filepath)
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000659 os.remove(os.path.dirname(filepath))
660 raise
661
662
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000663def update_gmaven(gmaven_artifacts_list):
664 artifacts = [GMavenArtifact(artifact) for artifact in gmaven_artifacts_list]
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000665 for artifact in artifacts:
666 if artifact.version == 'latest':
667 artifact.version = artifact.get_latest_version()
668
Saeid Farivar Asanjan54cd34e2021-10-01 16:47:54 +0000669 if not transform_maven_repos(['gmaven'], gmaven_dir, extract_res=False):
670 return []
671 return [artifact.key for artifact in artifacts]
672
673
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000674def update_androidx(target, build_id, local_file, include, exclude, beyond_corp):
675 """Fetches and extracts Jetpack library prebuilts.
676
677 Args:
678 target: Android build server target name, must be specified if local_file is empty
679 build_id: Optional Android build server ID, must be specified if local_file is empty
680 local_file: Optional local top-of-tree ZIP, must be specified if build_id is empty
681 include: List of Maven groupIds or unversioned artifact coordinates to include for
682 updates, ex. android.core or androidx.core:core
683 exclude: List of Maven groupIds or unversioned artifact coordinates to exclude from
684 updates, ex. android.core or androidx.core:core
685 beyond_corp: Whether to use BeyondCorp-compatible artifact fetcher
686 Returns:
687 True if successful, false otherwise.
688 """
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400689 if build_id:
Anthony Chenacbb4872018-07-02 11:22:48 -0700690 repo_file = 'top-of-tree-m2repository-all-%s.zip' % build_id.fs_id
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000691 repo_dir = fetch_and_extract(target, build_id.url_id, repo_file, beyond_corp, None)
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400692 else:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000693 repo_dir = fetch_and_extract(target, None, None, beyond_corp, local_file)
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400694 if not repo_dir:
695 print_e('Failed to extract AndroidX repository')
696 return False
697
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000698 prepend_path = os.path.relpath('update_prebuilts/prepend_androidx_license', start=temp_dir)
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400699
Tony Mak0f658752019-07-19 11:11:05 +0100700 # Transform the repo archive into a Makefile-compatible format.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000701 if not transform_maven_repos([repo_dir], androidx_dir, extract_res=False, include=include,
702 exclude=exclude, prepend=prepend_path):
Tony Mak0f658752019-07-19 11:11:05 +0100703 return False
704
705 # Import JavaPlugins.bp in Android.bp.
706 makefile = os.path.join(androidx_dir, 'Android.bp')
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000707 with open(makefile, 'a+') as f:
Tony Mak0f658752019-07-19 11:11:05 +0100708 f.write('\nbuild = ["JavaPlugins.bp"]\n')
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000709
710 # Keep OWNERs file, JavaPlugins.bp file, and TEST_MAPPING files untouched.
Nick Anthonybac2fca2022-11-03 18:56:57 +0000711 files_to_restore = [androidx_owners, java_plugins_bp_path, test_mapping_file,
712 compose_test_mapping_file]
713 for file_to_restore in files_to_restore:
714 # Ignore any output or error - these files are not gauranteed to exist, but
715 # if they do, we want to restore them.
716 subprocess.call(['git', 'restore', file_to_restore],
717 stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
Tony Mak0f658752019-07-19 11:11:05 +0100718
719 return True
Jeff Gastonbbd6bfc2018-03-27 17:35:49 -0400720
Alan Viverette6dc45752020-04-16 14:56:20 +0000721
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000722def update_jetifier(target, build_id, beyond_corp):
723 """
724 Fetches and extracts Jetifier tool prebuilts.
725
726 Args:
727 target: Android build server target name
728 build_id: Android build server ID
729 beyond_corp: Whether to use BeyondCorp-compatible artifact fetcher
730 Return:
731 Whether the prebuilt was successfully updated.
732 """
Jeff Gaston782c3e32018-02-06 14:36:17 -0500733 repo_file = 'jetifier-standalone.zip'
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000734 repo_dir = fetch_and_extract(target, build_id.url_id, repo_file, beyond_corp)
Jeff Gaston782c3e32018-02-06 14:36:17 -0500735 if not repo_dir:
736 print_e('Failed to extract Jetifier')
737 return False
738
739 rm(jetifier_dir)
Jeff Gaston553a4372018-03-29 18:34:22 -0400740 mv(os.path.join(repo_dir, 'jetifier-standalone'), jetifier_dir)
741 os.chmod(os.path.join(jetifier_dir, 'bin', 'jetifier-standalone'), 0o755)
Jeff Gaston782c3e32018-02-06 14:36:17 -0500742 return True
743
Alan Viverette7e897e22018-03-09 15:24:10 -0500744
Alan Viverette6dc45752020-04-16 14:56:20 +0000745def update_constraint(local_file):
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000746 """
747 Extracts ConstraintLayout library prebuilts.
748
749 Args:
750 local_file: local Maven repository ZIP containing library artifacts
751 Return:
752 Whether the prebuilts were successfully updated.
753 """
Jeff Gaston9edf86c2018-04-18 13:45:23 -0400754 repo_dir = extract_artifact(local_file)
755 if not repo_dir:
Alan Viverette6dc45752020-04-16 14:56:20 +0000756 print_e('Failed to extract Constraint Layout')
Jeff Gaston9edf86c2018-04-18 13:45:23 -0400757 return False
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000758 return transform_maven_repos([repo_dir], os.path.join(extras_dir, 'constraint-layout-x'),
759 extract_res=False)
Jeff Gaston9edf86c2018-04-18 13:45:23 -0400760
Alan Viverette45837092017-05-12 14:50:53 -0400761
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000762def update_material(local_file):
763 """
764 Extracts Material Design Components library prebuilts.
765
766 Args:
767 local_file: local Maven repository ZIP containing library artifacts
768 Return:
769 Whether the prebuilts were successfully updated.
770 """
771 design_dir = extract_artifact(local_file)
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400772 if not design_dir:
Alan Viverette6dc45752020-04-16 14:56:20 +0000773 print_e('Failed to extract Material Design Components')
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400774 return False
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000775 return transform_maven_repos([design_dir], os.path.join(extras_dir, 'material-design-x'),
776 extract_res=False)
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400777
Jeff Gaston6e7e7502018-04-04 00:22:45 -0400778
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000779def update_framework(target, build_id, sdk_dir, beyond_corp):
Anton Hansson83f92172020-03-26 11:12:03 +0000780 api_scope_list = ['public', 'system', 'test', 'module-lib', 'system-server']
Sundong Ahn66091f22018-08-29 18:54:28 +0900781 if sdk_dir == 'current':
782 api_scope_list.append('core')
783
784 for api_scope in api_scope_list:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000785 target_dir = os.path.join(sdk_dir, api_scope)
Sundong Ahn66091f22018-08-29 18:54:28 +0900786 if api_scope == 'core':
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000787 artifact_to_path = {'core.current.stubs.jar': os.path.join(target_dir, 'android.jar')}
Sundong Ahn66091f22018-08-29 18:54:28 +0900788 else:
Paul Duffin6815a312021-10-28 13:02:51 +0100789 artifact_to_path = {
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000790 'apistubs/android/' + api_scope + '/*.jar': os.path.join(target_dir, '*'),
Paul Duffin6815a312021-10-28 13:02:51 +0100791 }
792 if api_scope == 'public' or api_scope == 'module-lib':
793 # Distinct core-for-system-modules.jar files are only provided
794 # for the public and module-lib API surfaces.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000795 artifact_to_path[
796 'system-modules/' + api_scope + '/core-for-system-modules.jar'] = os.path.join(
797 target_dir, '*')
Anton Hansson1d01a032018-04-09 10:29:37 +0100798
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000799 if not fetch_artifacts(target, build_id, artifact_to_path, beyond_corp):
Anton Hansson1d01a032018-04-09 10:29:37 +0100800 return False
801
Jiyong Park1d1c9632018-05-29 17:45:27 +0900802 if api_scope == 'public':
Anton Hansson1d01a032018-04-09 10:29:37 +0100803 # Fetch a few artifacts from the public sdk.
Sundong Ahn66091f22018-08-29 18:54:28 +0900804 artifact = 'sdk-repo-linux-platforms-%s.zip' % build_id.fs_id
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000805 artifact_path = fetch_artifact(target, build_id.url_id, artifact, beyond_corp)
Anton Hansson9709fd42018-04-03 16:52:13 +0100806 if not artifact_path:
807 return False
Anton Hansson1d01a032018-04-09 10:29:37 +0100808
809 with zipfile.ZipFile(artifact_path) as zipFile:
Colin Crossd338d702020-07-10 19:17:54 -0700810 extra_files = [
811 'android.jar',
812 'framework.aidl',
813 'uiautomator.jar',
Colin Crossd338d702020-07-10 19:17:54 -0700814 'data/annotations.zip',
815 'data/api-versions.xml']
816 for filename in extra_files:
Anton Hanssona26e4812020-03-25 12:54:39 +0000817 matches = list(filter(lambda path: filename in path, zipFile.namelist()))
818 if len(matches) != 1:
819 print_e('Expected 1 file named \'%s\' in zip %s, found %d' %
820 (filename, zipFile.filename, len(matches)))
821 return False
822 zip_path = matches[0]
823 src_path = zipFile.extract(zip_path)
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000824 dst_path = os.path.join(target_dir, filename)
Anton Hanssona26e4812020-03-25 12:54:39 +0000825 mv(src_path, dst_path)
Anton Hansson9709fd42018-04-03 16:52:13 +0100826
Anton Hansson73be1512021-06-24 10:56:05 +0100827 # Filtered API DB is currently only available for "public"
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000828 fetch_artifacts(target, build_id, {'api-versions-public-filtered.xml': os.path.join(
829 target_dir, 'data/api-versions-filtered.xml')}, beyond_corp)
Anton Hansson73be1512021-06-24 10:56:05 +0100830
Alan Viverettecd3de262017-08-14 09:51:30 -0400831 return True
Alan Viverette45837092017-05-12 14:50:53 -0400832
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000833
Sundong Ahncc34cc32018-07-11 15:18:47 +0900834def update_makefile(build_id):
835 template = '"%s",\n\
836 "current"'
837 makefile = os.path.join(git_dir, 'Android.bp')
838
839 with open(makefile, 'r+') as f:
840 contents = f.read().replace('"current"', template % build_id)
841 f.seek(0)
842 f.write(contents)
843
844 return True
Alan Viverette45837092017-05-12 14:50:53 -0400845
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000846
847def finalize_sdk(target, build_id, sdk_version, beyond_corp):
Anton Hansson1d01a032018-04-09 10:29:37 +0100848 target_finalize_dir = '%d' % sdk_version
Anton Hansson9709fd42018-04-03 16:52:13 +0100849
Anton Hanssonaa554c02020-04-30 14:06:20 +0100850 for api_scope in ['public', 'system', 'test', 'module-lib', 'system-server']:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000851 artifact_to_path = {f'apistubs/android/{api_scope}/api/*.txt': os.path.join(
852 target_finalize_dir, api_scope, 'api', '*')}
Sundong Ahn66091f22018-08-29 18:54:28 +0900853
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000854 if not fetch_artifacts(target, build_id, artifact_to_path, beyond_corp):
Sundong Ahn66091f22018-08-29 18:54:28 +0900855 return False
856
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000857 return update_framework(target, build_id, target_finalize_dir, beyond_corp) and update_makefile(
858 target_finalize_dir)
Anton Hansson9709fd42018-04-03 16:52:13 +0100859
Anton Hansson9709fd42018-04-03 16:52:13 +0100860
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000861def update_framework_current(target, build_id, beyond_corp):
862 return update_framework(target, build_id, current_path, beyond_corp)
Anton Hansson9709fd42018-04-03 16:52:13 +0100863
864
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000865def update_buildtools(target, arch, build_id, beyond_corp):
Jeff Gaston13e38412018-02-06 14:45:36 -0500866 artifact_path = fetch_and_extract(target, build_id.url_id,
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000867 f'sdk-repo-{arch}-build-tools-{build_id.fs_id}.zip',
868 beyond_corp)
Alan Viverettec1c32b62017-12-20 09:40:36 -0500869 if not artifact_path:
870 return False
871
872 top_level_dir = os.listdir(artifact_path)[0]
873 src_path = os.path.join(artifact_path, top_level_dir)
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000874 dst_path = os.path.join(buildtools_dir, arch)
Colin Cross20648d32021-02-12 13:30:51 -0800875
876 # There are a few libraries that have been manually added to the
877 # build tools, copy them from the destination back to the source
878 # before the destination is overwritten.
879 files_to_save = (
880 'lib64/libconscrypt_openjdk_jni.dylib',
881 'lib64/libconscrypt_openjdk_jni.so',
882 'bin/lib64/libwinpthread-1.dll',
883 )
884 for file in files_to_save:
885 src_file = os.path.join(dst_path, file)
886 dst_file = os.path.join(src_path, file)
887 if os.path.exists(dst_path):
888 mv(src_file, dst_file)
889
Alan Viverettec1c32b62017-12-20 09:40:36 -0500890 mv(src_path, dst_path)
891
892 # Move all top-level files to /bin and make them executable
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000893 bin_path = os.path.join(dst_path, 'bin')
894 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 -0500895 for file in top_level_files:
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000896 src_file = os.path.join(dst_path, file)
897 dst_file = os.path.join(bin_path, file)
Alan Viverettec1c32b62017-12-20 09:40:36 -0500898 mv(src_file, dst_file)
899 os.chmod(dst_file, 0o755)
900
Colin Cross6673ceb2021-02-12 13:14:14 -0800901 # Make the files under lld-bin executable
902 lld_bin_files = os.listdir(os.path.join(dst_path, 'lld-bin'))
903 for file in lld_bin_files:
904 os.chmod(os.path.join(dst_path, 'lld-bin', file), 0o755)
905
Alan Viverettec1c32b62017-12-20 09:40:36 -0500906 # Remove renderscript
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000907 rm(os.path.join(dst_path, 'renderscript'))
Alan Viverettec1c32b62017-12-20 09:40:36 -0500908
909 return True
910
911
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000912def has_uncommitted_changes():
Jeff Gastoncc296a82018-03-23 14:33:24 -0400913 try:
914 # Make sure we don't overwrite any pending changes.
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000915 diff_command = f'cd {git_dir} && git diff --quiet'
916 subprocess.check_call(diff_command, shell=True)
917 subprocess.check_call(f'{diff_command} --cached', shell=True)
Jeff Gastoncc296a82018-03-23 14:33:24 -0400918 return False
919 except subprocess.CalledProcessError:
920 return True
921
922
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000923def main():
924 parser = argparse.ArgumentParser(
925 description='Update current prebuilts')
926 parser.add_argument(
927 'source', nargs='?',
928 help='Build server build ID or local Maven ZIP file')
929 parser.add_argument(
930 '-m', '--material', action='store_true',
931 help='If specified, updates only Material Design Components')
932 parser.add_argument(
933 '-c', '--constraint', action='store_true',
934 help='If specified, updates only Constraint Layout')
935 parser.add_argument(
936 '-j', '--jetifier', action='store_true',
937 help='If specified, updates only Jetifier')
938 parser.add_argument(
939 '-p', '--platform', action='store_true',
940 help='If specified, updates only the Android Platform')
941 parser.add_argument(
942 '-f', '--finalize_sdk', type=int,
943 help='Finalize the build as the specified SDK version. Must be used together with -e')
944 parser.add_argument(
945 '-e', '--finalize_extension', type=int,
946 help='Finalize the build as the specified extension SDK version. Must be used together with -f')
947 parser.add_argument('--bug', type=int, help='The bug number to add to the commit message.')
948 parser.add_argument(
949 '--sdk_target',
950 default=framework_sdk_target,
951 help='If specified, the name of the build target from which to retrieve the SDK when -p or -f '
952 'is specified.')
953 parser.add_argument(
954 '-b', '--buildtools', action='store_true',
955 help='If specified, updates only the Build Tools')
956 parser.add_argument(
957 '-x', '--androidx', action='store_true',
958 help='If specified, updates only the Jetpack (androidx) libraries excluding those covered by '
959 'other arguments')
960 parser.add_argument(
961 '--include', action='append', default=[],
962 help='If specified with -x, includes the specified Jetpack library Maven group or artifact for '
963 'updates. Applied before exclude.')
964 parser.add_argument(
965 '--exclude', action='append', default=[],
966 help='If specified with -x, excludes the specified Jetpack library Maven group or artifact '
967 'from updates')
968 parser.add_argument(
969 '-g', '--gmaven', action='store_true',
970 help='If specified, updates only the artifact from GMaven libraries excluding those covered by '
971 'other arguments')
972 parser.add_argument(
973 '--commit-first', action='store_true',
974 help='If specified, then if uncommited changes exist, commit before continuing')
975 parser.add_argument(
976 '--beyond-corp', action='store_true',
977 help='If specified, then fetch artifacts with tooling that works on BeyondCorp devices')
Anton Hansson4bcebac2022-04-07 17:23:18 +0100978
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000979 rm(temp_dir)
Alan Viveretted4527e62017-05-11 15:03:25 -0400980
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000981 args = parser.parse_args()
Jeff Gastoncc296a82018-03-23 14:33:24 -0400982
Anvesh Renikindi18680e62022-10-26 19:15:50 +0000983 # Validate combinations of arguments.
984 if not args.source and (args.platform or args.buildtools or args.jetifier
985 or args.androidx or args.material or args.finalize_sdk
986 or args.constraint):
987 parser.error('You must specify a build ID or local Maven ZIP file')
988 sys.exit(1)
989 if not (args.gmaven or args.platform or args.buildtools or args.jetifier
990 or args.androidx or args.material or args.finalize_sdk
991 or args.finalize_extension or args.constraint):
992 parser.error('You must specify at least one target to update')
993 sys.exit(1)
994 if (args.finalize_sdk is None) != (args.finalize_extension is None):
995 parser.error('Either both or neither of -e and -f must be specified.')
996 sys.exit(1)
997 if args.finalize_sdk and not args.bug:
998 parser.error('Specifying a bug ID with --bug is required when finalizing an SDK.')
999 sys.exit(1)
Alan Viveretted4527e62017-05-11 15:03:25 -04001000
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001001 # Validate the build environment for POM-dependent targets.
1002 if (args.constraint or args.material or args.androidx or args.gmaven) \
1003 and which('pom2bp') is None:
1004 parser.error('Cannot find pom2bp in path; please run lunch to set up build environment. '
1005 'You may also need to run \'m pom2bp\' if it hasn\'t been built already.')
1006 sys.exit(1)
Anton Hansson57a1b142022-04-07 17:27:41 +01001007
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001008 # Validate the git status.
1009 if has_uncommitted_changes():
1010 if args.commit_first:
1011 subprocess.check_call(f'cd {git_dir} && git add -u', shell=True)
1012 subprocess.check_call(f'cd {git_dir} && git commit -m \'save working state\'',
1013 shell=True)
1014 if has_uncommitted_changes():
1015 self_file = os.path.basename(__file__)
1016 print_e(f'FAIL: There are uncommitted changes here. Please commit or stash before '
1017 f'continuing, because {self_file} will run "git reset --hard" if execution fails')
1018 sys.exit(1)
Anton Hansson4bcebac2022-04-07 17:23:18 +01001019
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001020 if args.bug:
1021 commit_msg_suffix = '\n\nBug: {args.bug}'
Alan Viverette129555e2018-01-30 09:57:57 -05001022 else:
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001023 commit_msg_suffix = ''
Alan Viveretted4527e62017-05-11 15:03:25 -04001024
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001025 # Are we fetching a build ID or using a local file?
1026 build_id = None
1027 file = None
1028 if args.source:
1029 build_id = parse_build_id(args.source)
1030 if build_id is None:
1031 file = args.source
1032
Alan Viveretted4527e62017-05-11 15:03:25 -04001033 try:
Anvesh Renikindi18680e62022-10-26 19:15:50 +00001034 components = []
1035 if args.constraint:
1036 if update_constraint(file):
1037 components.append('Constraint Layout')
1038 else:
1039 print_e('Failed to update Constraint Layout, aborting...')
1040 sys.exit(1)
1041 if args.material:
1042 if update_material(file):
1043 components.append('Material Design Components')
1044 else:
1045 print_e('Failed to update Material Design Components, aborting...')
1046 sys.exit(1)
1047 if args.gmaven:
1048 updated_artifacts = update_gmaven(gmaven_artifacts)
1049 if updated_artifacts:
1050 components.append('\n'.join(updated_artifacts))
1051 else:
1052 print_e('Failed to update GMaven, aborting...')
1053 sys.exit(1)
1054 if args.androidx:
1055 if update_androidx('androidx', build_id, file, args.include, args.exclude,
1056 args.beyond_corp):
1057 components.append('AndroidX')
1058 else:
1059 print_e('Failed to update AndroidX, aborting...')
1060 sys.exit(1)
1061 if args.jetifier:
1062 if update_jetifier('androidx', build_id, args.beyond_corp):
1063 components.append('Jetifier')
1064 else:
1065 print_e('Failed to update Jetifier, aborting...')
1066 sys.exit(1)
1067 if args.platform or args.finalize_sdk:
1068 if update_framework_current(args.sdk_target, build_id, args.beyond_corp):
1069 components.append('platform SDK')
1070 else:
1071 print_e('Failed to update platform SDK, aborting...')
1072 sys.exit(1)
1073 if args.finalize_sdk:
1074 n = args.finalize_sdk
1075 if not finalize_sdk(args.sdk_target, build_id, n, args.beyond_corp):
1076 print_e('Failed to finalize SDK %d, aborting...' % n)
1077 sys.exit(1)
1078
1079 # We commit the finalized dir separately from the current sdk update.
1080 msg = f'Import final sdk version {n} from build {build_id.url_id}{commit_msg_suffix}'
1081 subprocess.check_call(['git', 'add', '%d' % n])
1082 subprocess.check_call(['git', 'add', 'Android.bp'])
1083 subprocess.check_call(['git', 'commit', '-m', msg])
1084
1085 # Finalize extension sdk level
1086 readme = (f'- {args.finalize_extension}: Finalized together with '
1087 'Android {args.finalize_sdk} (all modules)')
1088 cmd = extension_sdk_finalization_cmd.format(
1089 readme=readme,
1090 bug=args.bug,
1091 extension_version=args.finalize_extension,
1092 build_id=build_id.url_id)
1093 subprocess.check_call(shlex.split(cmd), cwd=repo_root_dir.resolve())
1094 if args.buildtools:
1095 if update_buildtools('sdk_mac', 'darwin', build_id, args.beyond_corp) \
1096 and update_buildtools('sdk', 'linux', build_id, args.beyond_corp) \
1097 and update_buildtools('sdk', 'windows', build_id, args.beyond_corp):
1098 components.append('build tools')
1099 else:
1100 print_e('Failed to update build tools, aborting...')
1101 sys.exit(1)
1102
1103 # Build the git commit.
1104 subprocess.check_call(['git', 'add', current_path, buildtools_dir])
1105
1106 # Build the commit message.
1107 components_msg = ', '.join(components)
1108 argv_msg = ' '.join(sys.argv)
1109 if not args.source and args.gmaven:
1110 src_msg = 'GMaven'
1111 elif not args.source.isnumeric():
1112 src_msg = 'local Maven ZIP'
1113 else:
1114 src_msg = f'build {build_id.url_id}'
1115 msg = f'Import {components_msg} from {src_msg}\n\n{argv_msg}{commit_msg_suffix}'
1116
1117 # Create the git commit.
1118 subprocess.check_call(['git', 'commit', '-q', '-m', msg])
1119
1120 if args.finalize_sdk:
1121 print('NOTE: Created three commits:')
1122 subprocess.check_call(['git', 'log', '-3', '--oneline'])
1123 else:
1124 print('Created commit:')
1125 subprocess.check_call(['git', 'log', '-1', '--oneline'])
1126 print('Remember to test this change before uploading it to Gerrit!')
1127
1128 finally:
1129 # Revert all stray files, including the downloaded zip.
1130 try:
1131 with open(os.devnull, 'w') as bitbucket:
1132 subprocess.check_call(['git', 'add', '-Af', '.'], stdout=bitbucket)
1133 subprocess.check_call(
1134 ['git', 'commit', '-m', 'COMMIT TO REVERT - RESET ME!!!', '--allow-empty'],
1135 stdout=bitbucket)
1136 subprocess.check_call(['git', 'reset', '--hard', 'HEAD~1'], stdout=bitbucket)
1137 except subprocess.CalledProcessError:
1138 print_e('ERROR: Failed cleaning up, manual cleanup required!!!')
1139
1140
1141# Add automatic entries to maven_to_make.
1142populate_maven_to_make(maven_to_make)
1143
1144if __name__ == '__main__':
1145 main()