#!/usr/bin/env python3
# Copyright (c) 2018, 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.

# Script for checking impact of a change by comparing the sizes of generated
# classes in an apk.

import glob
import optparse
import os
import shutil
import sys
import threading
import time
import zipfile

import toolhelper
import utils

USAGE = """%prog [options] app1 app2
  NOTE: This only makes sense if minification is disabled"""

MAX_THREADS = 40


def parse_options():
    result = optparse.OptionParser(usage=USAGE)
    result.add_option('--no-build',
                      help='Run without building first',
                      default=False,
                      action='store_true')
    result.add_option('--temp',
                      help='Temporary directory to store extracted classes in')
    result.add_option(
        '--use_code_size',
        help=
        'Use the size of code segments instead of the full size of the dex.',
        default=False,
        action='store_true')
    result.add_option(
        '--ignore_debug_info',
        help='Do not include debug info in the comparison.',
        default=False,
        action='store_true')
    result.add_option(
        '--report', help='Print comparison to this location instead of stdout')
    return result.parse_args()


def extract_apk(apk, output):
    if os.path.exists(output):
        shutil.rmtree(output)
    zipfile.ZipFile(apk).extractall(output)
    with utils.ChangedWorkingDirectory(output):
        dex = glob.glob('*.dex')
        return [os.path.join(output, dexfile) for dexfile in dex]


def ensure_exists(files):
    for f in files:
        if not os.path.exists(f):
            raise Exception('%s does not exist' % f)


def extract_classes(input, output, options):
    if os.path.exists(output):
        shutil.rmtree(output)
    os.makedirs(output)
    args = ['--file-per-class', '--output', output]
    if options.no_build:
        args.extend(['--no-build'])
    args.extend(input)
    extra_args = []
    if options.ignore_debug_info:
        extra_args.append('-Dcom.android.tools.r8.nullOutDebugInfo=1')
    if toolhelper.run('d8', args, extra_args=extra_args) is not 0:
        raise Exception('Failed running d8')


def get_code_size(path):
    segments = toolhelper.run('dexsegments', [path],
                              build=False,
                              return_stdout=True)
    for line in segments.splitlines():
        if 'Code' in line:
            # The code size line looks like:
            #  - Code: 264 / 4
            splits = line.split(' ')
            return int(splits[3])
    # Some classes has no code.
    return 0


class FileInfo:

    def __init__(self, path, root):
        self.path = path
        self.full_path = os.path.join(root, path)

    def __eq__(self, other):
        return self.full_path == other.full_path

    def set_size(self, use_code_size):
        if use_code_size:
            self.size = get_code_size(self.full_path)
        else:
            self.size = os.path.getsize(self.full_path)


def generate_file_info(path, options):
    file_info_map = {}
    with utils.ChangedWorkingDirectory(path):
        for root, dirs, files in os.walk('.'):
            for f in files:
                assert f.endswith('dex')
                file_path = os.path.join(root, f)
                entry = FileInfo(file_path, path)
                if not options.use_code_size:
                    entry.set_size(False)
                file_info_map[file_path] = entry
    threads = []
    file_infos = list(file_info_map.values()) if options.use_code_size else []
    while len(file_infos) > 0 or len(threads) > 0:
        for t in threads:
            if not t.is_alive():
                threads.remove(t)
        # sleep
        if len(threads) == MAX_THREADS or len(file_infos) == 0:
            time.sleep(0.5)
        while len(threads) < MAX_THREADS and len(file_infos) > 0:
            info = file_infos.pop()
            print('Added %s for size calculation' % info.full_path)
            t = threading.Thread(target=info.set_size,
                                 args=(options.use_code_size,))
            threads.append(t)
            t.start()
        print('Missing %s files, threads=%s ' % (len(file_infos), len(threads)))

    return file_info_map


def print_info(app, app_files, only_in_app, bigger_in_app, output):
    output.write('Only in %s\n' % app)
    only_app_sorted = sorted(only_in_app,
                             key=lambda a: app_files[a].size,
                             reverse=True)
    output.write('\n'.join(
        ['  %s %s bytes' % (x, app_files[x].size) for x in only_app_sorted]))
    output.write('\n\n')
    output.write('Bigger in %s\n' % app)
    # Sort by the percentage diff compared to size
    percent = lambda a: (0.0 + bigger_in_app.get(a)) / app_files.get(a
                                                                    ).size * 100
    for bigger in sorted(bigger_in_app, key=percent, reverse=True):
        output.write('  {0:.3f}% {1} bytes {2}\n'.format(
            percent(bigger), bigger_in_app[bigger], bigger))
    output.write('\n\n')


def compare(app1_classes_dir, app2_classes_dir, app1, app2, options):
    app1_files = generate_file_info(app1_classes_dir, options)
    app2_files = generate_file_info(app2_classes_dir, options)
    only_in_app1 = [k for k in app1_files if k not in app2_files]
    only_in_app2 = [k for k in app2_files if k not in app1_files]
    in_both = [k for k in app2_files if k in app1_files]
    assert len(app1_files) == len(only_in_app1) + len(in_both)
    assert len(app2_files) == len(only_in_app2) + len(in_both)
    bigger_in_app1 = {}
    bigger_in_app2 = {}
    same_size = []
    for f in in_both:
        app1_entry = app1_files[f]
        app2_entry = app2_files[f]
        if app1_entry.size > app2_entry.size:
            bigger_in_app1[f] = app1_entry.size - app2_entry.size
        elif app2_entry.size > app1_entry.size:
            bigger_in_app2[f] = app2_entry.size - app1_entry.size
        else:
            same_size.append(f)
    output = open(options.report, 'w') if options.report else sys.stdout
    print_info(app1, app1_files, only_in_app1, bigger_in_app1, output)
    print_info(app2, app2_files, only_in_app2, bigger_in_app2, output)
    output.write('Same size\n')
    output.write('\n'.join(['  %s' % x for x in same_size]))
    if options.report:
        output.close()


def Main():
    (options, args) = parse_options()
    if len(args) is not 2:
        print(args)
        print('Takes exactly two arguments, the two apps to compare')
        return 1
    app1 = args[0]
    app2 = args[1]
    ensure_exists([app1, app2])
    with utils.TempDir() as temporary:
        # If a temp dir is passed in, use that instead of the generated temporary
        output = options.temp if options.temp else temporary
        ensure_exists([output])
        app1_input = [app1]
        app2_input = [app2]
        if app1.endswith('apk'):
            app1_input = extract_apk(app1, os.path.join(output, 'app1'))
        if app2.endswith('apk'):
            app2_input = extract_apk(app2, os.path.join(output, 'app2'))
        app1_classes_dir = os.path.join(output, 'app1_classes')
        app2_classes_dir = os.path.join(output, 'app2_classes')

        extract_classes(app1_input, app1_classes_dir, options)
        extract_classes(app2_input, app2_classes_dir, options)
        compare(app1_classes_dir, app2_classes_dir, app1, app2, options)


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