| #!/usr/bin/env python3 | 
 | # Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file | 
 | # for details. All rights reserved. Use of this source code is governed by a | 
 | # BSD-style license that can be found in the LICENSE file. | 
 |  | 
 | import argparse | 
 | import hashlib | 
 | import jdk | 
 | import subprocess | 
 | import sys | 
 | import zipfile | 
 | from os import makedirs | 
 | from os.path import basename | 
 | from os.path import join | 
 | from shutil import copyfile | 
 | from shutil import make_archive | 
 | from shutil import move | 
 | from string import Template | 
 |  | 
 | import gradle | 
 | import utils | 
 |  | 
 | LICENSETEMPLATE = Template(""" | 
 |     <license> | 
 |       <name>$name</name> | 
 |       <url>$url</url> | 
 |       <distribution>repo</distribution> | 
 |     </license>""") | 
 |  | 
 | R8_POMTEMPLATE = Template("""<project | 
 |     xmlns="http://maven.apache.org/POM/4.0.0" | 
 |     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | 
 |     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | 
 |   <modelVersion>4.0.0</modelVersion> | 
 |   <groupId>com.android.tools</groupId> | 
 |   <artifactId>r8</artifactId> | 
 |   <version>$version</version> | 
 |   <name>D8 dexer and R8 shrinker</name> | 
 |   <description> | 
 |   D8 dexer and R8 shrinker. | 
 |   </description> | 
 |   <url>http://r8.googlesource.com/r8</url> | 
 |   <inceptionYear>2016</inceptionYear> | 
 |   <licenses> | 
 |     <license> | 
 |       <name>BSD-3-Clause</name> | 
 |       <url>https://opensource.org/licenses/BSD-3-Clause</url> | 
 |       <distribution>repo</distribution> | 
 |     </license>$library_licenses | 
 |   </licenses> | 
 |   <dependencies> | 
 |   </dependencies> | 
 |   <developers> | 
 |     <developer> | 
 |       <name>The Android Open Source Project</name> | 
 |     </developer> | 
 |   </developers> | 
 |   <scm> | 
 |     <connection> | 
 |       https://r8.googlesource.com/r8.git | 
 |     </connection> | 
 |     <url> | 
 |       https://r8.googlesource.com/r8 | 
 |     </url> | 
 |   </scm> | 
 | </project> | 
 | """) | 
 |  | 
 | DESUGAR_CONFIGUATION_POMTEMPLATE = Template("""<project | 
 |     xmlns="http://maven.apache.org/POM/4.0.0" | 
 |     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | 
 |     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | 
 |   <modelVersion>4.0.0</modelVersion> | 
 |   <groupId>com.android.tools</groupId> | 
 |   <artifactId>$artifactId</artifactId> | 
 |   <version>$version</version> | 
 |   <name>D8 configuration to desugar desugar_jdk_libs</name> | 
 |   <description> | 
 |   D8 configuration to desugar desugar_jdk_libs. | 
 |   </description> | 
 |   <url>http://r8.googlesource.com/r8</url> | 
 |   <inceptionYear>2019</inceptionYear> | 
 |   <licenses> | 
 |     <license> | 
 |       <name>BSD-3-Clause</name> | 
 |       <url>https://opensource.org/licenses/BSD-3-Clause</url> | 
 |       <distribution>repo</distribution> | 
 |     </license> | 
 |   </licenses> | 
 |   <developers> | 
 |     <developer> | 
 |       <name>The Android Open Source Project</name> | 
 |     </developer> | 
 |   </developers> | 
 |   <scm> | 
 |     <connection> | 
 |       https://r8.googlesource.com/r8.git | 
 |     </connection> | 
 |     <url> | 
 |       https://r8.googlesource.com/r8 | 
 |     </url> | 
 |   </scm> | 
 | </project> | 
 | """) | 
 |  | 
 |  | 
 | def parse_options(argv): | 
 |     result = argparse.ArgumentParser() | 
 |     result.add_argument('--out', help='The zip file to output') | 
 |     group = result.add_mutually_exclusive_group() | 
 |     group.add_argument( | 
 |         '--desugar-configuration', | 
 |         action='store_true', | 
 |         help='Build desugar library configuration (original JDK-8)') | 
 |     group.add_argument( | 
 |         '--desugar-configuration-jdk8', | 
 |         action='store_true', | 
 |         help='Build desugar library configuration (original JDK-8)') | 
 |     group.add_argument( | 
 |         '--desugar-configuration-jdk11-legacy', | 
 |         action='store_true', | 
 |         help='Build desugar library configuration (JDK-11 legacy)') | 
 |     group.add_argument( | 
 |         '--desugar-configuration-jdk11-minimal', | 
 |         action='store_true', | 
 |         help='Build desugar library configuration (JDK-11 minimal)') | 
 |     group.add_argument('--desugar-configuration-jdk11', | 
 |                        action='store_true', | 
 |                        help='Build desugar library configuration (JDK-11)') | 
 |     group.add_argument('--desugar-configuration-jdk11-nio', | 
 |                        action='store_true', | 
 |                        help='Build desugar library configuration (JDK-11 nio)') | 
 |     return result.parse_args(argv) | 
 |  | 
 |  | 
 | def determine_version(): | 
 |     version_file = join(utils.SRC_ROOT, 'com', 'android', 'tools', 'r8', | 
 |                         'Version.java') | 
 |     with open(version_file, 'r') as file: | 
 |         for line in file: | 
 |             if 'final String LABEL ' in line: | 
 |                 result = line[line.find('"') + 1:] | 
 |                 result = result[:result.find('"')] | 
 |                 return result | 
 |     raise Exception('Unable to determine version.') | 
 |  | 
 |  | 
 | def generate_library_licenses(): | 
 |     artifact_prefix = '- artifact: ' | 
 |     license_prefix = 'license: ' | 
 |     licenses = [] | 
 |     license_url_prefix = 'licenseUrl: ' | 
 |     license_urls = [] | 
 |     # The ./LIBRARY-LICENSE file is a simple yaml file, which for each dependency | 
 |     # has the following information: | 
 |     # | 
 |     # - artifact: <maven artifact>  // in the form <group-id>:<artifact-id>:+ | 
 |     #   name: <name of dependency> | 
 |     #   copyrightHolder: <name of copyright holder> | 
 |     #   license: <license name> | 
 |     #   licenseUrl: <url to license test> | 
 |     # | 
 |     # E.g. for Guava: | 
 |     # | 
 |     # - artifact: com.google.guava:guava:+ | 
 |     #   name: Guava Google Core Libraries for Java | 
 |     #   copyrightHolder: The Guava Authors | 
 |     #   license: The Apache Software License, Version 2.0 | 
 |     #   licenseUrl: http://www.apache.org/licenses/LICENSE-2.0.txt | 
 |     # | 
 |     # This file should always be up to date as the build will fail if it | 
 |     # is does not have information for all dependencies. | 
 |     with open('LIBRARY-LICENSE', 'r') as file: | 
 |         name = None | 
 |         url = None | 
 |         for line in file: | 
 |             trimmed = line.strip() | 
 |             # Collect license name and url for each artifact. They must come in | 
 |             # pairs for each artifact. | 
 |             if trimmed.startswith(artifact_prefix): | 
 |                 assert not name | 
 |                 assert not url | 
 |             if trimmed.startswith(license_prefix): | 
 |                 name = trimmed[len(license_prefix):] | 
 |             if trimmed.startswith(license_url_prefix): | 
 |                 url = trimmed[len(license_url_prefix):] | 
 |             # Licenses come in name/url pairs. When both are present add pair | 
 |             # to collected licenses if either name or url has not been recorded yet, | 
 |             # as some licenses with slightly different names point to the same url. | 
 |             if name and url: | 
 |                 if (not name in licenses) or (not url in license_urls): | 
 |                     licenses.append(name) | 
 |                     license_urls.append(url) | 
 |                 name = None | 
 |                 url = None | 
 |             assert len(licenses) == len(license_urls) | 
 |     result = '' | 
 |     for i in range(len(licenses)): | 
 |         name = licenses[i] | 
 |         url = license_urls[i] | 
 |         result += LICENSETEMPLATE.substitute(name=name, url=url) | 
 |     return result | 
 |  | 
 |  | 
 | def write_default_r8_pom_file(pom_file, version): | 
 |     write_pom_file(R8_POMTEMPLATE, pom_file, version) | 
 |  | 
 |  | 
 | def write_pom_file(template, | 
 |                    pom_file, | 
 |                    version, | 
 |                    artifact_id=None, | 
 |                    library_licenses=''): | 
 |     version_pom = (template.substitute(artifactId=artifact_id, | 
 |                                        version=version, | 
 |                                        library_licenses=library_licenses) | 
 |                    if artifact_id else template.substitute( | 
 |                        version=version, library_licenses=library_licenses)) | 
 |     with open(pom_file, 'w') as file: | 
 |         file.write(version_pom) | 
 |  | 
 |  | 
 | def hash_for(file, hash): | 
 |     with open(file, 'rb') as f: | 
 |         while True: | 
 |             # Read chunks of 1MB | 
 |             chunk = f.read(2**20) | 
 |             if not chunk: | 
 |                 break | 
 |             hash.update(chunk) | 
 |     return hash.hexdigest() | 
 |  | 
 |  | 
 | def write_md5_for(file): | 
 |     hexdigest = hash_for(file, hashlib.md5()) | 
 |     with (open(file + '.md5', 'w')) as file: | 
 |         file.write(hexdigest) | 
 |  | 
 |  | 
 | def write_sha1_for(file): | 
 |     hexdigest = hash_for(file, hashlib.sha1()) | 
 |     with (open(file + '.sha1', 'w')) as file: | 
 |         file.write(hexdigest) | 
 |  | 
 |  | 
 | def generate_maven_zip(name, version, pom_file, jar_file, out): | 
 |     with utils.TempDir() as tmp_dir: | 
 |         # Create the base maven version directory | 
 |         version_dir = join(tmp_dir, utils.get_maven_path(name, version)) | 
 |         makedirs(version_dir) | 
 |         # Write the pom file. | 
 |         pom_file_location = join(version_dir, name + '-' + version + '.pom') | 
 |         copyfile(pom_file, pom_file_location) | 
 |         # Write the jar file. | 
 |         jar_file_location = join(version_dir, name + '-' + version + '.jar') | 
 |         copyfile(jar_file, jar_file_location) | 
 |         # Create check sums. | 
 |         write_md5_for(jar_file_location) | 
 |         write_md5_for(pom_file_location) | 
 |         write_sha1_for(jar_file_location) | 
 |         write_sha1_for(pom_file_location) | 
 |         # Zip it up - make_archive will append zip to the file, so remove. | 
 |         assert out.endswith('.zip') | 
 |         base_no_zip = out[0:len(out) - 4] | 
 |         make_archive(base_no_zip, 'zip', tmp_dir) | 
 |  | 
 |  | 
 | def generate_r8_maven_zip(out, version_file=None, skip_gradle_build=False): | 
 |     if not skip_gradle_build: | 
 |         gradle.RunGradle([utils.GRADLE_TASK_R8LIB, '-Pno_internal']) | 
 |     version = determine_version() | 
 |     with utils.TempDir() as tmp_dir: | 
 |         file_copy = join(tmp_dir, 'copy_of_jar.jar') | 
 |         copyfile(utils.R8LIB_JAR, file_copy) | 
 |  | 
 |         if version_file: | 
 |             with zipfile.ZipFile(file_copy, 'a') as zip: | 
 |                 zip.write(version_file, basename(version_file)) | 
 |  | 
 |         # Generate the pom file. | 
 |         pom_file = join(tmp_dir, 'r8.pom') | 
 |         write_pom_file(R8_POMTEMPLATE, | 
 |                        pom_file, | 
 |                        version, | 
 |                        library_licenses=generate_library_licenses()) | 
 |         # Write the maven zip file. | 
 |         generate_maven_zip('r8', version, pom_file, file_copy, out) | 
 |  | 
 |  | 
 | # Write the desugaring configuration of a jar file with the following content: | 
 | #  java/ | 
 | #    util/ | 
 | #      <java.util conversions classes> | 
 | #    time/ | 
 | #      <java.time conversions classes> | 
 | #  META-INF/ | 
 | #    desugar/ | 
 | #      d8/ | 
 | #        desugar.json | 
 | #        lint/ | 
 | #          <lint files> | 
 | def generate_jar_with_desugar_configuration(configuration, implementation, | 
 |                                             conversions, destination): | 
 |     with utils.TempDir() as tmp_dir: | 
 |         # Add conversion classes. | 
 |         with zipfile.ZipFile(conversions, 'r') as conversions_zip: | 
 |             conversions_zip.extractall(tmp_dir) | 
 |  | 
 |         # Add configuration. | 
 |         configuration_dir = join(tmp_dir, 'META-INF', 'desugar', 'd8') | 
 |         makedirs(configuration_dir) | 
 |         copyfile(configuration, join(configuration_dir, 'desugar.json')) | 
 |  | 
 |         # Add lint configuartion. | 
 |         lint_dir = join(configuration_dir, 'lint') | 
 |         makedirs(lint_dir) | 
 |         cmd = [ | 
 |             jdk.GetJavaExecutable(), '-cp', utils.R8_JAR, | 
 |             'com.android.tools.r8.ir.desugar.desugaredlibrary.lint.GenerateDesugaredLibraryLintFiles', | 
 |             configuration, implementation, lint_dir, | 
 |             utils.get_android_jar(34, 0) | 
 |         ] | 
 |         utils.PrintCmd(cmd) | 
 |         subprocess.check_call(cmd) | 
 |  | 
 |         # Add LICENSE file. | 
 |         copyfile(join(utils.REPO_ROOT, 'LICENSE'), join(tmp_dir, 'LICENSE')) | 
 |  | 
 |         make_archive(destination, 'zip', tmp_dir) | 
 |         move(destination + '.zip', destination) | 
 |  | 
 |  | 
 | def convert_desugar_configuration(configuration, conversions, implementation, | 
 |                                   machine_configuration): | 
 |     cmd = [ | 
 |         jdk.GetJavaExecutable(), '-cp', utils.R8_JAR, | 
 |         'com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.DesugaredLibraryConverter', | 
 |         configuration, implementation, conversions, | 
 |         utils.get_android_jar(33, 0), machine_configuration | 
 |     ] | 
 |     subprocess.check_call(cmd) | 
 |  | 
 |  | 
 | # Generate the maven zip for the configuration to desugar desugar_jdk_libs. | 
 | def generate_desugar_configuration_maven_zip(out, configuration, implementation, | 
 |                                              conversions): | 
 |     with utils.TempDir() as tmp_dir: | 
 |         (name, version) = utils.desugar_configuration_name_and_version( | 
 |             configuration, False) | 
 |  | 
 |         if (not version.startswith("1.")): | 
 |             machine_configuration = join(tmp_dir, "machine.json") | 
 |             convert_desugar_configuration(configuration, conversions, | 
 |                                           implementation, machine_configuration) | 
 |             configuration = machine_configuration | 
 |  | 
 |         # Generate the pom file. | 
 |         pom_file = join(tmp_dir, 'desugar_configuration.pom') | 
 |         write_pom_file(DESUGAR_CONFIGUATION_POMTEMPLATE, | 
 |                        pom_file, | 
 |                        version, | 
 |                        artifact_id=name) | 
 |         # Generate the jar with the configuration file. | 
 |         jar_file = join(tmp_dir, 'desugar_configuration.jar') | 
 |         generate_jar_with_desugar_configuration(configuration, implementation, | 
 |                                                 conversions, jar_file) | 
 |         # Write the maven zip file. | 
 |         generate_maven_zip(name, version, pom_file, jar_file, out) | 
 |  | 
 |  | 
 | def main(argv): | 
 |     options = parse_options(argv) | 
 |     if options.out == None: | 
 |         raise Exception('Need to supply output zip with --out.') | 
 |     if options.desugar_configuration or options.desugar_configuration_jdk8: | 
 |         generate_desugar_configuration_maven_zip( | 
 |             options.out, utils.DESUGAR_CONFIGURATION, | 
 |             utils.DESUGAR_IMPLEMENTATION, | 
 |             utils.LIBRARY_DESUGAR_CONVERSIONS_LEGACY_ZIP) | 
 |     elif options.desugar_configuration_jdk11_legacy: | 
 |         generate_desugar_configuration_maven_zip( | 
 |             options.out, utils.DESUGAR_CONFIGURATION_JDK11_LEGACY, | 
 |             utils.DESUGAR_IMPLEMENTATION_JDK11, | 
 |             utils.LIBRARY_DESUGAR_CONVERSIONS_LEGACY_ZIP) | 
 |     elif options.desugar_configuration_jdk11_minimal: | 
 |         generate_desugar_configuration_maven_zip( | 
 |             options.out, utils.DESUGAR_CONFIGURATION_JDK11_MINIMAL, | 
 |             utils.DESUGAR_IMPLEMENTATION_JDK11, | 
 |             utils.LIBRARY_DESUGAR_CONVERSIONS_ZIP) | 
 |     elif options.desugar_configuration_jdk11: | 
 |         generate_desugar_configuration_maven_zip( | 
 |             options.out, utils.DESUGAR_CONFIGURATION_JDK11, | 
 |             utils.DESUGAR_IMPLEMENTATION_JDK11, | 
 |             utils.LIBRARY_DESUGAR_CONVERSIONS_ZIP) | 
 |     elif options.desugar_configuration_jdk11_nio: | 
 |         generate_desugar_configuration_maven_zip( | 
 |             options.out, utils.DESUGAR_CONFIGURATION_JDK11_NIO, | 
 |             utils.DESUGAR_IMPLEMENTATION_JDK11, | 
 |             utils.LIBRARY_DESUGAR_CONVERSIONS_ZIP) | 
 |     else: | 
 |         generate_r8_maven_zip(options.out) | 
 |  | 
 |  | 
 | if __name__ == "__main__": | 
 |     exit(main(sys.argv[1:])) |