1#!/usr/bin/env python 2# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file 3# for details. All rights reserved. Use of this source code is governed by a 4# BSD-style license that can be found in the LICENSE file. 5 6# Take a file where each line is a tab-separated list of arguments for DX (or 7# CompatDX/D8) and create a self-contained directory with all the input files 8# and a script which replays the same DX invocations as the original list. 9# 10# Usage: 11# 12# create_dx_replay.py <dx-args-script> <output-dir> 13# 14# The <dx-args-script> is a text file where each line contains tab-separated 15# arguments for a DX (CompatDX/D8) call. 16# The script 'tools/test_android_cts.py' can log DX invocations during an AOSP 17# build to such a file. Use 'test_android_cts.py --tool=d8 --d8log=<file> ...'. 18 19from __future__ import print_function 20from os.path import join, isdir, exists, basename 21from os import rmdir 22from shutil import copy2 23import argparse 24import os 25import stat 26import sys 27 28import utils 29 30IN_SUBDIR = 'in' # subdirectory for the local copy of the input files 31OUT_SUBDIR = 'out' # subdirectory prefix for the output of DX/CompatDX 32REPLAY_SCRIPT_NAME = 'replay_script.py' 33 34# This function will be called with arguments of the original DX invocation. It 35# copies the original input files into the local input directory and replaces 36# the references in orig_args to the local input files. 37# Returns the new line to be appended to the replay script. 38def process_line(out_dir, input_counter, orig_args): 39 args = [] 40 inputs = [] 41 for arg in orig_args: 42 if arg.startswith('--output='): 43 continue # nothing to do, just skip this arg 44 if arg.startswith('--'): 45 args.append(arg) 46 else: 47 # 'arg' is the path of an input file: copy arg to local dir with 48 # a new, unique name 49 if isdir(arg): 50 raise IOError("Adding directories ('{}') to the replay script is not" 51 " implemented.".format(arg)) 52 elif not exists(arg): 53 print("The input file to DX/CompatDX does not exist: '{}'.".format(arg)) 54 55 input_file = '{}_{}'.format(input_counter, basename(arg)) 56 57 copy2(arg, join(out_dir, join(IN_SUBDIR, input_file))) 58 inputs.append(input_file) 59 60 return 'call_dx({}, {}, {})\n'.format(input_counter, args, inputs) 61 62 63def parse_arguments(): 64 parser = argparse.ArgumentParser( 65 description = 'Creates a self-contained directory for playing back a ' 66 ' sequence of DX (CompatDX) calls.') 67 parser.add_argument('dx_call_log', 68 help = 'File containing tab-separated arguments for a DX call on each' 69 ' line.') 70 parser.add_argument('output_dir', 71 help = 'Target path the create the self-contained directory at.') 72 return parser.parse_args() 73 74def Main(): 75 args = parse_arguments() 76 77 if isdir(args.output_dir): 78 rmdir(args.output_dir) # make sure to write only to empty out dir 79 80 utils.makedirs_if_needed(join(args.output_dir, IN_SUBDIR)) 81 82 # create the first lines of the replay script 83 replay_script = \ 84"""#!/usr/bin/env python 85import os 86import shutil 87import subprocess 88import sys 89 90SCRIPT_DIR = os.path.abspath(os.path.normpath(os.path.join(__file__, '..'))) 91IN_SUBDIR = '{}' 92OUT_SUBDIR = '{}' 93 94def call_dx(input_counter, args, inputs): 95 out_dir = os.path.join(SCRIPT_DIR, OUT_SUBDIR, str(input_counter)) 96 if not os.path.isdir(out_dir): 97 os.makedirs(out_dir) 98 full_inputs = [os.path.join(SCRIPT_DIR, IN_SUBDIR, i) for i in inputs] 99 subprocess.check_call(sys.argv[1:] + args + ['--output=' + out_dir] 100 + full_inputs) 101 102if len(sys.argv) < 2: 103 raise IOError('Usage: create_dx_replay.py <dx-command>' 104 ' # can be multiple args') 105abs_out_dir = os.path.join(SCRIPT_DIR, OUT_SUBDIR) 106if os.path.isdir(abs_out_dir): 107 shutil.rmtree(abs_out_dir) 108 109""".format(IN_SUBDIR, OUT_SUBDIR) 110 111 with open(args.dx_call_log) as f: 112 lines = f.read().splitlines() 113 114 input_counter = 1 115 for line in lines: 116 replay_script += \ 117 process_line(args.output_dir, input_counter, line.split('\t')) 118 input_counter += 1 119 120 script_file = join(args.output_dir, REPLAY_SCRIPT_NAME) 121 with open(script_file, 'w') as f: 122 f.write(replay_script) 123 124 # chmod +x for script_file 125 st = os.stat(script_file) 126 os.chmod(script_file, st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) 127 128if __name__ == '__main__': 129 sys.exit(Main()) 130