blob: f8d81b69355a455ce72c1512cadcd5daef57071d [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2020 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""A script to generate build.gradle from template and run fetch_all.py
More specifically, to generate build.gradle:
- It downloads the index page for the latest androidx snapshot from
https://androidx.dev/snapshots/latest/artifacts
- It replaces {{androidx_repository_url}} with the URL for the latest snapshot
- For each dependency, it looks up the version in the index page's HTML and
substitutes the version into {{androidx_dependency_version}}.
Extra args after -- are passed directly to fetch_all.py.
"""
import argparse
import contextlib
import json
import logging
import os
import pathlib
import re
import shutil
import sys
import subprocess
import tempfile
from urllib import request
import zipfile
_SRC_PATH = pathlib.Path(__file__).resolve().parents[2]
_ANDROIDX_PATH = _SRC_PATH / 'third_party/androidx'
_CIPD_PATH = _ANDROIDX_PATH / 'cipd'
_BOM_NAME = 'bill_of_materials.json'
_EXTRACT_SCRIPT_PATH = _ANDROIDX_PATH / 'extract_and_commit_extras.py'
sys.path.insert(1, str(_SRC_PATH / 'build/autoroll'))
import fetch_util
# URL to artifacts in latest androidx snapshot.
_ANDROIDX_LATEST_SNAPSHOT_ARTIFACTS_URL = 'https://androidx.dev/snapshots/latest/artifacts'
# When androidx roller is breaking, and a fix is not imminent, use this to pin a
# broken library to an old known-working version.
# * Find working versions from prior androidx roll commit descriptions.
# * The first element of each tuple is the path to the artifact of the latest
# version of the library. It could change if the version is rev'ed in a new
# snapshot.
# * The second element is a URL to replace the file with. Find the URL for older
# versions of libraries by looking through the artifacts for the older version
# (e.g.: https://androidx.dev/snapshots/builds/8545498/artifacts)
_OVERRIDES = [
# Example:
#('androidx_core_core/core-1.9.0-SNAPSHOT.aar',
# 'https://androidx.dev/snapshots/builds/8545498/artifacts/repository/'
# 'androidx/core/core/1.8.0-SNAPSHOT/core-1.8.0-20220505.122105-1.aar'),
]
# Set this to the build_id to pin all libraries to a given version.
# Useful when pinning a single library would cause issues, but you do not want
# to pause the auto-roller because other teams want to add / remove libraries.
# Example: '8545498'
_LATEST_VERSION_OVERRIDE = ''
_FILES_TO_COMMIT = [
'additional_readme_paths.json',
'bill_of_materials.json',
'BUILD.gn',
'build.gradle',
]
def _get_latest_androidx_version():
androidx_artifacts_response = request.urlopen(
_ANDROIDX_LATEST_SNAPSHOT_ARTIFACTS_URL)
# Get the versioned url from the redirect destination.
androidx_artifacts_url = androidx_artifacts_response.url
androidx_artifacts_response.close()
logging.info('URL for the latest build info: %s', androidx_artifacts_url)
# Strip '/repository' from pattern.
resolved_snapshot_repository_url_pattern = (
fetch_util.make_androidx_maven_url('([0-9]*)').rsplit('/', 1)[0])
match = re.match(resolved_snapshot_repository_url_pattern,
androidx_artifacts_url)
assert match is not None
version = match.group(1)
logging.info('Resolved latest androidx version to %s', version)
return version
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('-v',
'--verbose',
dest='verbose_count',
default=0,
action='count',
help='Verbose level (multiple times for more)')
parser.add_argument('--local-repo',
help='Path to a locally androidx maven repo to use '
'instead of fetching the latest.')
parser.add_argument(
'--local',
action='store_true',
help='If passed then we will run the extract_and_commit_extras.py '
'script and will not try rolling to the latest snapshot but reprocess '
'the project at the current androidx.dev snapshot.')
parser.add_argument(
'--use-bom',
action='store_true',
help='If passed then we will use the existing bill_of_materials.json '
'instead of resolving the latest androidx (faster but might resolve '
'incorrect versions if deps are added/removed).')
args, extra_args = parser.parse_known_args()
logging.basicConfig(
level=logging.WARNING - 10 * args.verbose_count,
format='%(levelname).1s %(relativeCreated)6d %(message)s')
if args.local_repo:
version = 'local'
androidx_snapshot_repository_url = ('file://' +
os.path.abspath(args.local_repo))
else:
if _LATEST_VERSION_OVERRIDE:
version = _LATEST_VERSION_OVERRIDE
elif args.local:
version = fetch_util.get_current_androidx_version()
else:
version = _get_latest_androidx_version()
androidx_snapshot_repository_url = (
fetch_util.make_androidx_maven_url(version))
# Prepend '0' to version to avoid conflicts with previous version format.
version = 'cr-0' + version
if args.use_bom:
version_map_str = fetch_util.generate_version_map_str(_ANDROIDX_PATH /
_BOM_NAME)
else:
version_map_str = ''
fetch_util.fill_template(
_ANDROIDX_PATH / 'build.gradle.template',
_ANDROIDX_PATH / 'build.gradle',
version_overrides=version_map_str,
androidx_repository_url=androidx_snapshot_repository_url)
# Overrides do not work with local snapshots since the repository_url is
# different.
if not args.local_repo:
for subpath, url in _OVERRIDES:
extra_args += ['--override-artifact', f'{subpath}:{url}']
os.makedirs(_CIPD_PATH, exist_ok=True)
# gclient/cipd extract files as read only.
subprocess.run(['chmod', '-R', '+w', _CIPD_PATH])
fetch_util.run_fetch_all(android_deps_dir=_ANDROIDX_PATH,
output_subdir='cipd',
extra_args=extra_args,
verbose_count=args.verbose_count)
version_map_str = fetch_util.generate_version_map_str(_CIPD_PATH /
_BOM_NAME)
# Regenerate the build.gradle file filling in the the version map so that
# runs of the main project do not have to revalutate androidx versions.
fetch_util.fill_template(
_ANDROIDX_PATH / 'build.gradle.template',
_CIPD_PATH / 'build.gradle',
version_overrides=version_map_str,
androidx_repository_url=androidx_snapshot_repository_url)
version_txt_path = os.path.join(_CIPD_PATH, 'VERSION.txt')
with open(version_txt_path, 'w') as f:
f.write(version)
to_commit_zip_path = _CIPD_PATH / 'to_commit.zip'
file_map = {f: f'third_party/androidx/{f}' for f in _FILES_TO_COMMIT}
fetch_util.create_to_commit_zip(output_path=to_commit_zip_path,
package_root=_CIPD_PATH,
dirnames=['libs'],
absolute_file_map=file_map)
if args.local:
subprocess.run([
_EXTRACT_SCRIPT_PATH, '--cipd-package-path', _CIPD_PATH,
'--no-git-add'
],
check=True)
fetch_util.write_cipd_yaml(package_root=_CIPD_PATH,
package_name=fetch_util.ANDROIDX_CIPD_PACKAGE,
version=version,
output_path=_CIPD_PATH / 'cipd.yaml')
if __name__ == '__main__':
main()