|  | #!/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. | 
|  |  | 
|  | # Take a file where each line is a tab-separated list of arguments for DX (or | 
|  | # D8) and create a self-contained directory with all the input files | 
|  | # and a script which replays the same DX invocations as the original list. | 
|  | # | 
|  | # Usage: | 
|  | # | 
|  | #     create_dx_replay.py <dx-args-script> <output-dir> | 
|  | # | 
|  | # The <dx-args-script> is a text file where each line contains tab-separated | 
|  | # arguments for a DX (D8) call. | 
|  | # The script 'tools/test_android_cts.py' can log DX invocations during an AOSP | 
|  | # build to such a file. Use 'test_android_cts.py --tool=d8 --d8log=<file> ...'. | 
|  |  | 
|  | from __future__ import print_function | 
|  | from os.path import join, isdir, exists, basename | 
|  | from os import rmdir | 
|  | from shutil import copy2 | 
|  | import argparse | 
|  | import os | 
|  | import stat | 
|  | import sys | 
|  |  | 
|  | import utils | 
|  |  | 
|  | IN_SUBDIR = 'in' # subdirectory for the local copy of the input files | 
|  | OUT_SUBDIR = 'out' # subdirectory prefix for the output of DX | 
|  | REPLAY_SCRIPT_NAME = 'replay_script.py' | 
|  |  | 
|  | # This function will be called with arguments of the original DX invocation. It | 
|  | # copies the original input files into the local input directory and replaces | 
|  | # the references in orig_args to the local input files. | 
|  | # Returns the new line to be appended to the replay script. | 
|  | def process_line(out_dir, input_counter, orig_args): | 
|  | args = [] | 
|  | inputs = [] | 
|  | for arg in orig_args: | 
|  | if arg.startswith('--output='): | 
|  | continue # nothing to do, just skip this arg | 
|  | if arg.startswith('--'): | 
|  | args.append(arg) | 
|  | else: | 
|  | # 'arg' is the path of an input file: copy arg to local dir with | 
|  | # a new, unique name | 
|  | if isdir(arg): | 
|  | raise IOError("Adding directories ('{}') to the replay script is not" | 
|  | " implemented.".format(arg)) | 
|  | elif not exists(arg): | 
|  | print("The input file to DX does not exist: '{}'.".format(arg)) | 
|  |  | 
|  | input_file = '{}_{}'.format(input_counter, basename(arg)) | 
|  |  | 
|  | copy2(arg, join(out_dir, join(IN_SUBDIR, input_file))) | 
|  | inputs.append(input_file) | 
|  |  | 
|  | return 'call_dx({}, {}, {})\n'.format(input_counter, args, inputs) | 
|  |  | 
|  |  | 
|  | def parse_arguments(): | 
|  | parser = argparse.ArgumentParser( | 
|  | description = 'Creates a self-contained directory for playing back a ' | 
|  | ' sequence of DX calls.') | 
|  | parser.add_argument('dx_call_log', | 
|  | help = 'File containing tab-separated arguments for a DX call on each' | 
|  | ' line.') | 
|  | parser.add_argument('output_dir', | 
|  | help = 'Target path the create the self-contained directory at.') | 
|  | return parser.parse_args() | 
|  |  | 
|  | def Main(): | 
|  | args = parse_arguments() | 
|  |  | 
|  | if isdir(args.output_dir): | 
|  | rmdir(args.output_dir) # make sure to write only to empty out dir | 
|  |  | 
|  | utils.makedirs_if_needed(join(args.output_dir, IN_SUBDIR)) | 
|  |  | 
|  | # create the first lines of the replay script | 
|  | replay_script = \ | 
|  | """#!/usr/bin/env python3 | 
|  | import os | 
|  | import shutil | 
|  | import subprocess | 
|  | import sys | 
|  |  | 
|  | SCRIPT_DIR = os.path.abspath(os.path.normpath(os.path.join(__file__, '..'))) | 
|  | IN_SUBDIR = '{}' | 
|  | OUT_SUBDIR = '{}' | 
|  |  | 
|  | def call_dx(input_counter, args, inputs): | 
|  | out_dir = os.path.join(SCRIPT_DIR, OUT_SUBDIR, str(input_counter)) | 
|  | if not os.path.isdir(out_dir): | 
|  | os.makedirs(out_dir) | 
|  | full_inputs = [os.path.join(SCRIPT_DIR, IN_SUBDIR, i) for i in inputs] | 
|  | subprocess.check_call(sys.argv[1:] + args + ['--output=' + out_dir] | 
|  | + full_inputs) | 
|  |  | 
|  | if len(sys.argv) < 2: | 
|  | raise IOError('Usage: create_dx_replay.py <dx-command>' | 
|  | ' # can be multiple args') | 
|  | abs_out_dir = os.path.join(SCRIPT_DIR, OUT_SUBDIR) | 
|  | if os.path.isdir(abs_out_dir): | 
|  | shutil.rmtree(abs_out_dir) | 
|  |  | 
|  | """.format(IN_SUBDIR, OUT_SUBDIR) | 
|  |  | 
|  | with open(args.dx_call_log) as f: | 
|  | lines = f.read().splitlines() | 
|  |  | 
|  | input_counter = 1 | 
|  | for line in lines: | 
|  | replay_script += \ | 
|  | process_line(args.output_dir, input_counter, line.split('\t')) | 
|  | input_counter += 1 | 
|  |  | 
|  | script_file = join(args.output_dir, REPLAY_SCRIPT_NAME) | 
|  | with open(script_file, 'w') as f: | 
|  | f.write(replay_script) | 
|  |  | 
|  | # chmod +x for script_file | 
|  | st = os.stat(script_file) | 
|  | os.chmod(script_file, st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | sys.exit(Main()) |