blob: 55f306c70e71a23f774a7e95f10e52ba6d169625 [file] [log] [blame]
Peter Kotwicz2b85bd3d2020-10-01 22:29:491#!/usr/bin/env python3
2
Avi Drissman3f1ea442022-09-08 15:42:013# Copyright 2020 The Chromium Authors
Peter Kotwicz2b85bd3d2020-10-01 22:29:494# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
6"""A script to generate build.gradle from template and run fetch_all.py
7
8More specifically, to generate build.gradle:
Peter Wen1a004a02025-01-28 23:04:469 - It downloads the index page for the latest androidx snapshot from
10 https://androidx.dev/snapshots/latest/artifacts
Peter Kotwicz2b85bd3d2020-10-01 22:29:4911 - It replaces {{androidx_repository_url}} with the URL for the latest snapshot
Peter Wen1a004a02025-01-28 23:04:4612 - For each dependency, it looks up the version in the index page's HTML and
Peter Kotwicz2b85bd3d2020-10-01 22:29:4913 substitutes the version into {{androidx_dependency_version}}.
Peter Wen2e5944d2025-02-04 17:02:3214
15Extra args after -- are passed directly to fetch_all.py.
Peter Kotwicz2b85bd3d2020-10-01 22:29:4916"""
17
Haiyang Panace500932022-01-26 19:49:0318import argparse
Peter Kotwicz2b85bd3d2020-10-01 22:29:4919import contextlib
Mohamed Heikal811bb642025-02-25 20:03:5320import json
Haiyang Panace500932022-01-26 19:49:0321import logging
Peter Kotwicz2b85bd3d2020-10-01 22:29:4922import os
Andrew Grieveb5255af2024-06-06 17:03:1823import pathlib
Peter Kotwicz2b85bd3d2020-10-01 22:29:4924import re
Peter Kotwicz2b85bd3d2020-10-01 22:29:4925import shutil
Mohamed Heikal864fa342025-01-08 19:15:4526import sys
Peter Kotwicz2b85bd3d2020-10-01 22:29:4927import subprocess
28import tempfile
Peter Kotwicz4676d062020-10-22 06:04:1329from urllib import request
Peter Wenc90bbb72025-02-25 20:41:4430import zipfile
Peter Kotwicz2b85bd3d2020-10-01 22:29:4931
32_ANDROIDX_PATH = os.path.normpath(os.path.join(__file__, '..'))
Andrew Grieved8c97182024-06-28 18:37:3333_CIPD_PATH = os.path.join(_ANDROIDX_PATH, 'cipd')
Mohamed Heikal864fa342025-01-08 19:15:4534_SRC_PATH = os.path.normpath(os.path.join(_ANDROIDX_PATH, '..', '..'))
Mohamed Heikal811bb642025-02-25 20:03:5335_BOM_PATH = os.path.join(_CIPD_PATH, 'bill_of_materials.json')
Mohamed Heikal864fa342025-01-08 19:15:4536
37sys.path.insert(1, os.path.join(_SRC_PATH, 'third_party', 'depot_tools'))
38import gclient_eval
Peter Kotwicz2b85bd3d2020-10-01 22:29:4939
40_FETCH_ALL_PATH = os.path.normpath(
41 os.path.join(_ANDROIDX_PATH, '..', 'android_deps', 'fetch_all.py'))
42
Peter Wen1a004a02025-01-28 23:04:4643# URL to artifacts in latest androidx snapshot.
44_ANDROIDX_LATEST_SNAPSHOT_ARTIFACTS_URL = 'https://androidx.dev/snapshots/latest/artifacts'
Mohamed Heikal864fa342025-01-08 19:15:4545
46# Path to package listed in //DEPS
47_DEPS_PACKAGE = 'src/third_party/androidx/cipd'
48# CIPD package name
49_CIPD_PACKAGE = 'chromium/third_party/androidx'
Peter Kotwicz2b85bd3d2020-10-01 22:29:4950
Peter Kotwicz3fb0070e2021-02-11 07:37:3551# Snapshot repository URL with {{version}} placeholder.
52_SNAPSHOT_REPOSITORY_URL = 'https://androidx.dev/snapshots/builds/{{version}}/artifacts/repository'
53
Peter Wen1a004a02025-01-28 23:04:4654# When androidx roller is breaking, and a fix is not imminent, use this to pin a
Andrew Grieve2515bcbd2022-05-06 03:14:0755# broken library to an old known-working version.
Andrew Grievea03217f2022-05-12 16:05:2756# * The first element of each tuple is the path to the artifact of the latest
57# version of the library. It could change if the version is rev'ed in a new
58# snapshot.
59# * The second element is a URL to replace the file with. Find the URL for older
Peter Wen1a004a02025-01-28 23:04:4660# versions of libraries by looking through the artifacts for the older version
61# (e.g.: https://androidx.dev/snapshots/builds/8545498/artifacts)
Andrew Grieve2515bcbd2022-05-06 03:14:0762_OVERRIDES = [
Andrew Grievea03217f2022-05-12 16:05:2763 # Example:
Andrew Grieve2515bcbd2022-05-06 03:14:0764 #('androidx_core_core/core-1.9.0-SNAPSHOT.aar',
65 # 'https://androidx.dev/snapshots/builds/8545498/artifacts/repository/'
66 # 'androidx/core/core/1.8.0-SNAPSHOT/core-1.8.0-20220505.122105-1.aar'),
67]
68
Peter Kotwicz3fb0070e2021-02-11 07:37:3569
70def _build_snapshot_repository_url(version):
71 return _SNAPSHOT_REPOSITORY_URL.replace('{{version}}', version)
72
Peter Kotwicz2b85bd3d2020-10-01 22:29:4973
74def _parse_dir_list(dir_list):
75 """Computes 'library_group:library_name'->library_version mapping.
76
77 Args:
78 dir_list: List of androidx library directories.
79 """
80 dependency_version_map = dict()
81 for dir_entry in dir_list:
82 stripped_dir = dir_entry.strip()
83 if not stripped_dir.startswith('repository/androidx/'):
84 continue
85 dir_components = stripped_dir.split('/')
86 # Expected format:
Peter Wen1a004a02025-01-28 23:04:4687 # "repository/androidx/library_group/library_name/library_version"
88 if len(dir_components) < 5:
Peter Kotwicz2b85bd3d2020-10-01 22:29:4989 continue
Peter Wen1a004a02025-01-28 23:04:4690 dependency_package = 'androidx.' + '.'.join(dir_components[2:-2])
Peter Kotwicz4d3c39702021-03-25 21:48:2591 dependency_module = '{}:{}'.format(dependency_package,
Peter Wen1a004a02025-01-28 23:04:4692 dir_components[-2])
Peter Kotwicz2b85bd3d2020-10-01 22:29:4993 if dependency_module not in dependency_version_map:
Peter Wen1a004a02025-01-28 23:04:4694 dependency_version_map[dependency_module] = dir_components[-1]
Peter Kotwicz2b85bd3d2020-10-01 22:29:4995 return dependency_version_map
96
97
Peter Kotwicz2b85bd3d2020-10-01 22:29:4998@contextlib.contextmanager
99def _build_dir():
100 dirname = tempfile.mkdtemp()
101 try:
102 yield dirname
103 finally:
104 shutil.rmtree(dirname)
105
106
Mohamed Heikal864fa342025-01-08 19:15:45107def _get_latest_androidx_version():
Peter Wen1a004a02025-01-28 23:04:46108 androidx_artifacts_response = request.urlopen(
109 _ANDROIDX_LATEST_SNAPSHOT_ARTIFACTS_URL)
Mohamed Heikal864fa342025-01-08 19:15:45110 # Get the versioned url from the redirect destination.
Peter Wen1a004a02025-01-28 23:04:46111 androidx_artifacts_url = androidx_artifacts_response.url
112 androidx_artifacts_response.close()
113 logging.info('URL for the latest build info: %s', androidx_artifacts_url)
Mohamed Heikal864fa342025-01-08 19:15:45114 # Strip '/repository' from pattern.
115 resolved_snapshot_repository_url_pattern = (
116 _build_snapshot_repository_url('([0-9]*)').rsplit('/', 1)[0])
Peter Wen1a004a02025-01-28 23:04:46117 match = re.match(resolved_snapshot_repository_url_pattern,
118 androidx_artifacts_url)
119 assert match is not None
120 version = match.group(1)
Mohamed Heikal864fa342025-01-08 19:15:45121 return version
122
123
124def _query_cipd_tags(version):
125 cipd_output = subprocess.check_output(
126 ['cipd', 'describe', _CIPD_PACKAGE, '-version', version],
127 encoding='utf-8')
128 # Output looks like:
129 # Package: chromium/third_party/androidx
130 # Instance ID: gUjEawxv5mQO8yfbuC8W-rx4V3zYE-4LTWggXpZHI4sC
131 # Registered by: user:chromium-cipd-builder@chops-service-accounts.iam.gserviceaccount.com
132 # Registered at: 2025-01-06 17:54:48.034135 +0000 UTC
133 # Refs:
134 # latest
135 # Tags:
136 # details0:version-cr-012873390
137 # version:cr-012873390
138 lines = cipd_output.split('\n')
139 tags = {}
140 parsing_tags = False
141 for line in lines:
142 if not line.strip():
143 continue
144 if line.startswith('Tags:'):
145 parsing_tags = True
146 continue
147 if parsing_tags:
148 tag, value = line.strip().split(':', 1)
149 tags[tag] = value
150 return tags
151
152
153def _get_current_cipd_instance():
154 with open(os.path.join(_SRC_PATH, 'DEPS'), 'rt') as f:
155 gclient_dict = gclient_eval.Exec(f.read())
156 return gclient_eval.GetCIPD(gclient_dict, _DEPS_PACKAGE, _CIPD_PACKAGE)
157
158
159def _get_current_androidx_version():
160 cipd_instance = _get_current_cipd_instance()
161 cipd_tags = _query_cipd_tags(cipd_instance)
162 version_string = cipd_tags['version']
163 version = version_string[len('cr-0'):]
164 return version
165
166
Andrew Grieve10bbd552022-05-05 18:10:26167def _create_local_dir_list(repo_path):
168 repo_path = repo_path.rstrip('/')
169 prefix_len = len(repo_path) + 1
170 ret = []
Peter Wen1a004a02025-01-28 23:04:46171 for dirpath, _, _ in os.walk(repo_path):
172 ret.append(os.path.join('repository', dirpath[prefix_len:]))
Andrew Grieve10bbd552022-05-05 18:10:26173 return ret
Peter Kotwicz2b85bd3d2020-10-01 22:29:49174
175
Mohamed Heikal811bb642025-02-25 20:03:53176def _generate_version_map_str(bom_path):
177 bom = []
178 version_lines = []
179 with open(bom_path) as f:
180 bom = json.load(f)
181 for dep in bom:
182 line = f" versionCache['{dep['group']}:{dep['name']}'] = '{dep['version']}'"
183 version_lines.append(line)
184 return '\n'.join(sorted(version_lines))
185
186
Peter Wen1ba3d4d2025-02-25 21:46:37187def _process_build_gradle(template_path, output_path, androidx_repository_url,
188 version_overrides_str):
Peter Kotwicz2b85bd3d2020-10-01 22:29:49189 """Generates build.gradle from template.
190
191 Args:
Andrew Grieved8c97182024-06-28 18:37:33192 template_path: Path to build.gradle.template.
193 output_path: Path to build.gradle.
Peter Kotwicz2b85bd3d2020-10-01 22:29:49194 androidx_repository_url: URL of the maven repository.
Peter Wen1ba3d4d2025-02-25 21:46:37195 version_override_str: An optional list of pinned versions.
Peter Kotwicz2b85bd3d2020-10-01 22:29:49196 """
Mohamed Heikal811bb642025-02-25 20:03:53197 content = pathlib.Path(template_path).read_text()
198 content = content.replace('{{androidx_repository_url}}',
199 androidx_repository_url)
200 content = content.replace('{{version_overrides}}', version_overrides_str)
Andrew Grieveb5255af2024-06-06 17:03:18201 # build.gradle is not deleted after script has finished running. The file is in
Peter Kotwicz2b85bd3d2020-10-01 22:29:49202 # .gitignore and thus will be excluded from uploaded CLs.
Mohamed Heikal811bb642025-02-25 20:03:53203 pathlib.Path(output_path).write_text(content)
Peter Kotwicz2b85bd3d2020-10-01 22:29:49204
205
Andrew Grieve9c7d4ac2f2022-08-24 17:38:59206def _write_cipd_yaml(libs_dir, version, cipd_yaml_path, experimental=False):
Peter Kotwicza31339a2020-10-20 16:36:23207 """Writes cipd.yaml file at the passed-in path."""
208
209 lib_dirs = os.listdir(libs_dir)
210 if not lib_dirs:
211 raise Exception('No generated libraries in {}'.format(libs_dir))
212
Peter Kotwicz1ea22e12021-02-22 19:01:59213 data_files = [
214 'BUILD.gn', 'VERSION.txt', 'additional_readme_paths.json',
215 'build.gradle'
216 ]
Peter Kotwicza31339a2020-10-20 16:36:23217 for lib_dir in lib_dirs:
218 abs_lib_dir = os.path.join(libs_dir, lib_dir)
Andrew Grieved8c97182024-06-28 18:37:33219 androidx_rel_lib_dir = os.path.relpath(abs_lib_dir, _CIPD_PATH)
Peter Kotwicza31339a2020-10-20 16:36:23220 if not os.path.isdir(abs_lib_dir):
221 continue
222 lib_files = os.listdir(abs_lib_dir)
223 if not 'cipd.yaml' in lib_files:
224 continue
225
Peter Kotwicza6b3b9a2021-01-28 21:40:12226 for lib_file in lib_files:
227 if lib_file == 'cipd.yaml' or lib_file == 'OWNERS':
228 continue
229 data_files.append(os.path.join(androidx_rel_lib_dir, lib_file))
Peter Kotwicza31339a2020-10-20 16:36:23230
Andrew Grieve9c7d4ac2f2022-08-24 17:38:59231 if experimental:
232 package = 'experimental/google.com/' + os.getlogin() + '/androidx'
233 else:
234 package = 'chromium/third_party/androidx'
Peter Kotwicza31339a2020-10-20 16:36:23235 contents = [
mark a. foltzf87dfea2023-09-06 23:49:03236 '# Copyright 2021 The Chromium Authors',
Peter Kotwicza31339a2020-10-20 16:36:23237 '# Use of this source code is governed by a BSD-style license that can be',
238 '# found in the LICENSE file.',
Peter Kotwicz92548aa2021-02-18 15:12:58239 '# version: ' + version,
Andrew Grieve9c7d4ac2f2022-08-24 17:38:59240 'package: ' + package,
Peter Kotwicz3fb0070e2021-02-11 07:37:35241 'description: androidx',
242 'data:',
Peter Kotwicza31339a2020-10-20 16:36:23243 ]
244 contents.extend('- file: ' + f for f in data_files)
245
246 with open(cipd_yaml_path, 'w') as out:
247 out.write('\n'.join(contents))
248
249
Peter Kotwicz2b85bd3d2020-10-01 22:29:49250def main():
Haiyang Panace500932022-01-26 19:49:03251 parser = argparse.ArgumentParser(description=__doc__)
252 parser.add_argument('-v',
253 '--verbose',
254 dest='verbose_count',
255 default=0,
256 action='count',
257 help='Verbose level (multiple times for more)')
Andrew Grieve10bbd552022-05-05 18:10:26258 parser.add_argument('--local-repo',
259 help='Path to a locally androidx maven repo to use '
260 'instead of fetching the latest.')
Mohamed Heikal864fa342025-01-08 19:15:45261 parser.add_argument(
262 '--no-roll',
263 action='store_true',
264 help='If passed then we will not try rolling the '
265 'latest androidx but use the currently rolled version.')
Peter Wen1ba3d4d2025-02-25 21:46:37266 parser.add_argument(
267 '--use-bom',
268 action='store_true',
269 help='If passed then we will use the existing bill_of_materials.json '
270 'instead of resolving the latest androidx.')
Peter Wen2e5944d2025-02-04 17:02:32271 args, extra_args = parser.parse_known_args()
Haiyang Panace500932022-01-26 19:49:03272
273 logging.basicConfig(
274 level=logging.WARNING - 10 * args.verbose_count,
275 format='%(levelname).1s %(relativeCreated)6d %(message)s')
276
Andrew Grieve10bbd552022-05-05 18:10:26277 if args.local_repo:
278 version = 'local'
Andrew Grieve10bbd552022-05-05 18:10:26279 androidx_snapshot_repository_url = ('file://' +
280 os.path.abspath(args.local_repo))
281 else:
Mohamed Heikal864fa342025-01-08 19:15:45282 if args.no_roll:
283 version = _get_current_androidx_version()
284 logging.info('Resolved current androidx version to %s', version)
285 else:
286 version = _get_latest_androidx_version()
287 logging.info('Resolved latest androidx version to %s', version)
288
Andrew Grieve10bbd552022-05-05 18:10:26289 androidx_snapshot_repository_url = _build_snapshot_repository_url(
290 version)
Andrew Grieve9c7d4ac2f2022-08-24 17:38:59291 # Prepend '0' to version to avoid conflicts with previous version format.
292 version = 'cr-0' + version
293
Peter Wen1ba3d4d2025-02-25 21:46:37294 if args.use_bom:
295 version_map_str = _generate_version_map_str(_BOM_PATH)
296 else:
297 version_map_str = ''
298
Mohamed Heikal864fa342025-01-08 19:15:45299 if os.path.exists(_CIPD_PATH):
300 shutil.rmtree(_CIPD_PATH)
301 os.mkdir(_CIPD_PATH)
302
Andrew Grieved8c97182024-06-28 18:37:33303 _process_build_gradle(
304 os.path.join(_ANDROIDX_PATH, 'build.gradle.template'),
Peter Wen6fcf2d72025-02-12 15:34:26305 os.path.join(_CIPD_PATH, 'build.gradle'),
Peter Wen1ba3d4d2025-02-25 21:46:37306 androidx_snapshot_repository_url, version_map_str)
Andrew Grieve15c476e2023-02-10 19:57:31307 shutil.copyfile(os.path.join(_ANDROIDX_PATH, 'BUILD.gn.template'),
Andrew Grieved8c97182024-06-28 18:37:33308 os.path.join(_CIPD_PATH, 'BUILD.gn'))
Peter Kotwicz2b85bd3d2020-10-01 22:29:49309
310 fetch_all_cmd = [
Andrew Grieved8c97182024-06-28 18:37:33311 _FETCH_ALL_PATH, '--android-deps-dir', _CIPD_PATH,
Peter Kotwiczdabb89d072020-10-22 16:30:03312 '--ignore-vulnerabilities'
Andrew Grievee9bccea42023-02-10 19:56:25313 ] + ['-v'] * args.verbose_count
Peter Wen2e5944d2025-02-04 17:02:32314
315 # Filter out -- from the args to pass to fetch_all.py.
316 fetch_all_cmd += [a for a in extra_args if a != '--']
317
Andrew Grieve9c7d4ac2f2022-08-24 17:38:59318 # Overrides do not work with local snapshots since the repository_url is
319 # different.
320 if not args.local_repo:
321 for subpath, url in _OVERRIDES:
322 fetch_all_cmd += ['--override-artifact', f'{subpath}:{url}']
Mohamed Heikal864fa342025-01-08 19:15:45323 env = os.environ.copy()
324 # Silence the --local warning in fetch_all.py that is not applicable here.
325 env['SWARMING_TASK_ID'] = '1'
326 subprocess.run(fetch_all_cmd, check=True, env=env)
Peter Kotwicza31339a2020-10-20 16:36:23327
Mohamed Heikal811bb642025-02-25 20:03:53328 version_map_str = _generate_version_map_str(_BOM_PATH)
329
330 # Regenerate the build.gradle file filling in the the version map so that
331 # runs of the main project do not have to revalutate androidx versions.
332 _process_build_gradle(
333 os.path.join(_ANDROIDX_PATH, 'build.gradle.template'),
334 os.path.join(_CIPD_PATH, 'build.gradle'),
335 androidx_snapshot_repository_url, version_map_str)
336
Andrew Grieved8c97182024-06-28 18:37:33337 version_txt_path = os.path.join(_CIPD_PATH, 'VERSION.txt')
Andrew Grieve9c7d4ac2f2022-08-24 17:38:59338 with open(version_txt_path, 'w') as f:
339 f.write(version)
Peter Kotwicz92548aa2021-02-18 15:12:58340
Andrew Grieved8c97182024-06-28 18:37:33341 libs_dir = os.path.join(_CIPD_PATH, 'libs')
342 yaml_path = os.path.join(_CIPD_PATH, 'cipd.yaml')
343 _write_cipd_yaml(libs_dir,
344 version,
345 yaml_path,
Andrew Grieve9c7d4ac2f2022-08-24 17:38:59346 experimental=bool(args.local_repo))
Peter Kotwicz2b85bd3d2020-10-01 22:29:49347
Peter Wenc90bbb72025-02-25 20:41:44348 to_commit_paths = []
349 for root, _, files in os.walk(libs_dir):
350 for file in files:
351 # Avoid committing actual artifacts.
352 if file.endswith(('.aar', '.jar')):
353 continue
354 file_path = os.path.join(root, file)
355 file_path_in_committed = os.path.relpath(file_path, _CIPD_PATH)
356 to_commit_paths.append((file_path, file_path_in_committed))
357
358 files_in_tree = [
359 'additional_readme_paths.json', 'BUILD.gn', 'build.gradle'
360 ]
361 for file in files_in_tree:
362 file_path = os.path.join(_CIPD_PATH, file)
363 to_commit_paths.append(
364 (file_path, f'CHROMIUM_SRC/third_party/androidx/{file}'))
365
366 to_commit_zip_path = os.path.join(_CIPD_PATH, 'to_commit.zip')
367 with zipfile.ZipFile(to_commit_zip_path, 'w') as zip_file:
368 for filename, arcname in to_commit_paths:
369 zip_file.write(filename, arcname=arcname)
Peter Kotwicz2b85bd3d2020-10-01 22:29:49370
371if __name__ == '__main__':
372 main()