#!/usr/bin/env python3
# Copyright (c) 2021, 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 os
import subprocess
import shutil
import sys
import zipfile

import jdk
import utils
import zip_utils

VERSION_EXTRACTOR = """
import com.android.tools.r8.Version;
public class VersionExtractor {
  public static void main(String[] args) {
    System.out.println(Version.LABEL);
  }
}
"""


def parse_options():
    parser = argparse.ArgumentParser(description='Tag R8 Versions')
    parser.add_argument('--classpath',
                        action='append',
                        help='Dependencies to add to classpath')
    parser.add_argument('--debug-agent',
                        action='store_true',
                        default=False,
                        help='Create a socket for debugging')
    parser.add_argument('--replace-from-jar',
                        default=None,
                        help='Replace output jar with classes from this jar.')
    parser.add_argument(
        '--excldeps-variant',
        action='store_true',
        default=False,
        help='Mark this artifact as an "excldeps" variant of the compiler')
    parser.add_argument('--debug-variant',
                        action='store_true',
                        default=False,
                        help='Compile with debug flag')
    parser.add_argument('--disable-keep-annotations',
                        action='store_true',
                        default=False,
                        help='Disable keep annotations')
    parser.add_argument(
        '--exclude-api-database',
        action='store_true',
        default=False,
        help='Exclude api database (resources/new_api_database.ser)')
    parser.add_argument(
        '--lib',
        action='append',
        help='Additional libraries (JDK 1.8 rt.jar already included)')
    parser.add_argument('--output',
                        required=True,
                        help='The output path for the r8lib')
    parser.add_argument('--pg-conf', action='append', help='Keep configuration')
    parser.add_argument('--pg-map',
                        default=None,
                        help='Input map for distribution and composition')
    parser.add_argument('--r8jar', required=True, help='The R8 jar to compile')
    parser.add_argument('--r8-version-jar',
                        default=None,
                        help='The R8 jar to provide version')
    parser.add_argument('--r8compiler',
                        default='build/libs/r8_with_deps.jar',
                        help='The R8 compiler to use')
    return parser.parse_args()


def get_r8_version(r8jar):
    with utils.TempDir() as temp:
        name = os.path.join(temp, "VersionExtractor.java")
        fd = open(name, 'w')
        fd.write(VERSION_EXTRACTOR)
        fd.close()
        cmd = [jdk.GetJavacExecutable(), '-cp', r8jar, name]
        print(' '.join(cmd))
        cp_separator = ';' if utils.IsWindows() else ':'
        subprocess.check_call(cmd)
        output = subprocess.check_output([
            jdk.GetJavaExecutable(), '-cp',
            cp_separator.join([r8jar, os.path.dirname(name)]),
            'VersionExtractor'
        ]).decode('UTF-8').strip()
        if output == 'main':
            return subprocess.check_output(['git', 'rev-parse',
                                            'HEAD']).decode('UTF-8').strip()
        else:
            return output


# Used to delete the API database when building processkeeprules.jar.
def exclude_api_database(r8jar):
    if utils.IsWindows():
        try:
            zip_utils.remove_files_from_zip(
                [os.path.join('resources', 'new_api_database.ser')], r8jar)
        except Exception:
            # TODO(b/466252770): The removal of entries from ZIP files use
            # the zip executable, which is not installed on our Windows bots.
            pass
    else:
        zip_utils.remove_files_from_zip(
            [os.path.join('resources', 'new_api_database.ser')], r8jar)


# Used to move r8 assistant runtime files into r8.jar.
#
# These files need to be equivalent to the javac generated versions,
# so we copy them in after r8lib has been built.
def replace_in_jar(r8jar, replace_from):
    with utils.TempDir() as temp:
        result = os.path.join(temp, 'result.jar')
        skip_from_r8jar = set()
        with zipfile.ZipFile(result, 'w') as output_file:
            with zipfile.ZipFile(replace_from, 'r') as input_file:
                for zipinfo in input_file.infolist():
                    if zipinfo.filename.endswith('.class'):
                        data = input_file.read(zipinfo)
                        zipinfo.date_time = (1980, 1, 1, 0, 0, 0)
                        output_file.writestr(zipinfo, data)
                        skip_from_r8jar.add(zipinfo.filename)
                    else:
                        assert (zipinfo.filename == 'META-INF/MANIFEST.MF' or
                                zipinfo.is_dir())
            with zipfile.ZipFile(r8jar, 'r') as input_file:
                for zipinfo in input_file.infolist():
                    if not zipinfo.filename in skip_from_r8jar:
                        output_file.writestr(zipinfo, input_file.read(zipinfo))
        shutil.copyfile(result, r8jar)


def main():
    args = parse_options()
    if not os.path.exists(args.r8jar):
        print("Could not find jar: " + args.r8jar)
        return 1
    version = get_r8_version(
        args.r8_version_jar if args.r8_version_jar else args.r8jar)
    variant = '+excldeps' if args.excldeps_variant else ''
    map_id_template = version + variant
    source_file_template = 'R8_%MAP_ID_%MAP_HASH'
    # TODO(b/139725780): See if we can remove or lower the heap size (-Xmx8g).
    cmd = [jdk.GetJavaExecutable(), '-Xmx8g', '-ea']
    if args.debug_agent:
        cmd.extend([
            '-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005'
        ])
    cmd.append('-Dcom.android.tools.r8.enableKeepAnnotations=' +
               str(not args.disable_keep_annotations).lower())
    # TODO(b/356344563): Remove when this is default.
    cmd.append(
        '-Dcom.android.tools.r8.enableEmptyMemberRulesToDefaultInitRuleConversion=0'
    )
    cmd.append('-Dcom.android.tools.r8.tracereferences.obfuscateAllEnums')
    cmd.extend(['-cp', args.r8compiler, 'com.android.tools.r8.R8'])
    cmd.append(args.r8jar)
    if args.debug_variant:
        cmd.append('--debug')
    cmd.append('--classfile')
    cmd.extend(['--map-id-template', map_id_template])
    cmd.extend(['--source-file-template', source_file_template])
    cmd.extend(['--output', args.output])
    cmd.extend(['--pg-conf-output', args.output + '.config'])
    cmd.extend(['--pg-map-output', args.output + '.map'])
    cmd.extend(['--partition-map-output', args.output + '_map.zip'])
    cmd.extend(['--lib', jdk.GetDefaultJdkHome()])
    if args.pg_conf:
        for pgconf in args.pg_conf:
            cmd.extend(['--pg-conf', pgconf])
    if args.lib:
        for lib in args.lib:
            cmd.extend(['--lib', lib])
    if args.classpath:
        for cp in args.classpath:
            cmd.extend(['--classpath', cp])
    if args.pg_map:
        cmd.extend(['--pg-map', args.pg_map])
    print(' '.join(cmd))
    subprocess.check_call(cmd)
    if args.exclude_api_database:
        exclude_api_database(args.output)
    if args.replace_from_jar:
        replace_in_jar(args.output, args.replace_from_jar)


if __name__ == '__main__':
    sys.exit(main())
