| #!/usr/bin/env python | 
 | # 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. | 
 |  | 
 | # Run ProGuard and the DX or CompatDX (= D8) tool on GmsCore V10. | 
 |  | 
 | from __future__ import print_function | 
 | from glob import glob | 
 | from os import makedirs | 
 | from os.path import exists, join, splitext | 
 | from subprocess import check_call | 
 | import argparse | 
 | import fnmatch | 
 | import gmscore_data | 
 | import jdk | 
 | import os | 
 | import stat | 
 | import sys | 
 | import time | 
 |  | 
 | import gmail_data | 
 | import gmscore_data | 
 | import golem | 
 | import proguard | 
 | import utils | 
 | import youtube_data | 
 |  | 
 | APPS = ['gmscore', 'youtube'] | 
 | DX_JAR = join(utils.REPO_ROOT, 'tools', 'linux', 'dx', 'framework', 'dx.jar') | 
 |  | 
 | def parse_arguments(argv): | 
 |   parser = argparse.ArgumentParser( | 
 |       description = 'Run ProGuard and the DX tool on GmsCore V10.') | 
 |   parser.add_argument('--app', required = True, choices = APPS) | 
 |   parser.add_argument('--out', | 
 |       help = 'Output directory for the DX tool.', | 
 |       default = os.getcwd()) | 
 |   parser.add_argument('--compatdx', | 
 |       help = 'Use CompatDx (D8) instead of DX.', | 
 |       default = False, | 
 |       action = 'store_true') | 
 |   parser.add_argument('--golem', | 
 |       help = 'Link in third party dependencies.', | 
 |       default = False, | 
 |       action = 'store_true') | 
 |   parser.add_argument('--print-runtimeraw', | 
 |       metavar = 'BENCHMARKNAME', | 
 |       help = 'Print the line \'<BENCHMARKNAME>(RunTimeRaw): <elapsed>' + | 
 |              ' ms\' at the end where <elapsed> is the elapsed time in' + | 
 |              ' milliseconds.') | 
 |   parser.add_argument('--print-memoryuse', | 
 |       metavar='BENCHMARKNAME', | 
 |       help='Print the line \'<BENCHMARKNAME>(MemoryUse):' + | 
 |            ' <mem>\' at the end where <mem> is the peak' + | 
 |            ' peak resident set size (VmHWM) in bytes.') | 
 |   parser.add_argument('--print-dexsegments', | 
 |       metavar = 'BENCHMARKNAME', | 
 |       help = 'Print the sizes of individual dex segments as ' + | 
 |           '\'<BENCHMARKNAME>-<segment>(CodeSize): <bytes>\'') | 
 |   return parser.parse_args(argv) | 
 |  | 
 | def Main(argv): | 
 |   options = parse_arguments(argv) | 
 |   if options.golem: | 
 |     golem.link_third_party() | 
 |   utils.check_java_version() | 
 |   outdir = options.out | 
 |  | 
 |   if options.app == 'gmscore': | 
 |     version = 'v10' | 
 |     data = gmscore_data | 
 |     base = data.V10_BASE | 
 |   elif options.app == 'youtube': | 
 |     version = '12.22' | 
 |     data = youtube_data | 
 |     base = data.V12_22_BASE | 
 |   else: | 
 |     raise Exception('Unexpected') | 
 |  | 
 |  | 
 |   args = ['-forceprocessing'] | 
 |  | 
 |   if not outdir.endswith('.zip') and not outdir.endswith('.jar') \ | 
 |       and not exists(outdir): | 
 |     makedirs(outdir) | 
 |  | 
 |  | 
 |   values_deploy = data.VERSIONS[version]['deploy'] | 
 |   values_proguarded = data.VERSIONS[version]['proguarded'] | 
 |   assert 'pgconf' in values_deploy | 
 |  | 
 |   for pgconf in values_deploy['pgconf']: | 
 |     args.extend(['@' + pgconf]) | 
 |  | 
 |   # find seeds file | 
 |   inputs = data.VERSIONS[version]['proguarded']['inputs'] | 
 |   assert len(inputs) == 1 | 
 |   basename_wo_ext = splitext(os.path.basename(inputs[0]))[0] | 
 |   seeds_filename = basename_wo_ext + '.seeds' | 
 |  | 
 |   seeds_files = [] | 
 |   for root, dirnames, filenames in os.walk(join(base, 'blaze-out')): | 
 |     for filename in fnmatch.filter(filenames, seeds_filename): | 
 |         seeds_files.append(os.path.join(root, filename)) | 
 |   assert len(seeds_files) == 1 | 
 |  | 
 |   seeds_path = seeds_files[0] | 
 |   proguarded_jar_path = splitext(seeds_path)[0] + '.jar' | 
 |  | 
 |   # Remove write-protection from seeds file. The seeds file is an output of | 
 |   # ProGuard so it aborts if this is not writeable. | 
 |   st = os.stat(seeds_path) | 
 |   os.chmod(seeds_path, | 
 |       st.st_mode | stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH) | 
 |  | 
 |   t0 = time.time() | 
 |  | 
 |   proguard_memoryuse = None | 
 |  | 
 |   with utils.TempDir() as temp: | 
 |     track_memory_file = None | 
 |     if options.print_memoryuse: | 
 |       track_memory_file = join(temp, utils.MEMORY_USE_TMP_FILE) | 
 |     proguard.run( | 
 |         args, | 
 |         track_memory_file = track_memory_file, | 
 |         stdout=open(os.devnull, 'w')) | 
 |     if options.print_memoryuse: | 
 |       proguard_memoryuse = utils.grep_memoryuse(track_memory_file) | 
 |  | 
 |   # run dex on the result | 
 |   if options.compatdx: | 
 |     jar = utils.COMPATDX_JAR | 
 |   else: | 
 |     jar = DX_JAR | 
 |  | 
 |   with utils.TempDir() as temp: | 
 |     track_memory_file = None | 
 |     cmd = [] | 
 |     if options.print_memoryuse: | 
 |       track_memory_file = join(temp, utils.MEMORY_USE_TMP_FILE) | 
 |       cmd.extend(['tools/track_memory.sh', track_memory_file]) | 
 |     cmd.extend([jdk.GetJavaExecutable(), '-jar', jar, '--multi-dex', | 
 |         '--output=' + outdir]) | 
 |     if 'min-api' in values_proguarded: | 
 |       cmd.append('--min-sdk-version=' + values_proguarded['min-api']) | 
 |     cmd.extend(['--dex', proguarded_jar_path]) | 
 |     utils.PrintCmd(cmd); | 
 |     check_call(cmd) | 
 |     if options.print_memoryuse: | 
 |       dx_memoryuse = utils.grep_memoryuse(track_memory_file) | 
 |       print('{}(MemoryUse): {}' | 
 |           .format(options.print_memoryuse, | 
 |               max(proguard_memoryuse, dx_memoryuse))) | 
 |  | 
 |   if options.print_runtimeraw: | 
 |     print('{}(RunTimeRaw): {} ms' | 
 |         .format(options.print_runtimeraw, 1000.0 * (time.time() - t0))) | 
 |  | 
 |   if options.print_dexsegments: | 
 |     dex_files = glob(os.path.join(outdir, '*.dex')) | 
 |     utils.print_dexsegments(options.print_dexsegments, dex_files) | 
 |  | 
 | if __name__ == '__main__': | 
 |   sys.exit(Main(sys.argv[1:])) |