1*6777b538SAndroid Build Coastguard Worker#!/usr/bin/env vpython3 2*6777b538SAndroid Build Coastguard Worker# Copyright 2021 The Chromium Authors 3*6777b538SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*6777b538SAndroid Build Coastguard Worker# found in the LICENSE file. 5*6777b538SAndroid Build Coastguard Worker 6*6777b538SAndroid Build Coastguard Workerimport argparse 7*6777b538SAndroid Build Coastguard Workerimport os 8*6777b538SAndroid Build Coastguard Workerimport stat 9*6777b538SAndroid Build Coastguard Workerimport sys 10*6777b538SAndroid Build Coastguard Worker 11*6777b538SAndroid Build Coastguard Workersys.path.append( 12*6777b538SAndroid Build Coastguard Worker os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, 13*6777b538SAndroid Build Coastguard Worker 'build')) 14*6777b538SAndroid Build Coastguard Workerimport action_helpers 15*6777b538SAndroid Build Coastguard Worker 16*6777b538SAndroid Build Coastguard Worker 17*6777b538SAndroid Build Coastguard Workerdef _parse_args(args): 18*6777b538SAndroid Build Coastguard Worker description = 'Generator of bash scripts that can invoke the Python ' \ 19*6777b538SAndroid Build Coastguard Worker 'library for running Rust unit tests with support for ' \ 20*6777b538SAndroid Build Coastguard Worker 'Chromium test filters, sharding, and test output.' 21*6777b538SAndroid Build Coastguard Worker parser = argparse.ArgumentParser(description=description) 22*6777b538SAndroid Build Coastguard Worker parser.add_argument('--script-path', 23*6777b538SAndroid Build Coastguard Worker dest='script_path', 24*6777b538SAndroid Build Coastguard Worker help='Where to write the bash script.', 25*6777b538SAndroid Build Coastguard Worker metavar='FILEPATH', 26*6777b538SAndroid Build Coastguard Worker required=True) 27*6777b538SAndroid Build Coastguard Worker parser.add_argument('--exe-dir', 28*6777b538SAndroid Build Coastguard Worker dest='exe_dir', 29*6777b538SAndroid Build Coastguard Worker help='Directory where the wrapped executables are', 30*6777b538SAndroid Build Coastguard Worker metavar='PATH', 31*6777b538SAndroid Build Coastguard Worker required=True) 32*6777b538SAndroid Build Coastguard Worker parser.add_argument('--rust-test-executables', 33*6777b538SAndroid Build Coastguard Worker dest='rust_test_executables', 34*6777b538SAndroid Build Coastguard Worker help='File listing one or more executables to wrap. ' \ 35*6777b538SAndroid Build Coastguard Worker '(basenames - no .exe extension or directory)', 36*6777b538SAndroid Build Coastguard Worker metavar='FILEPATH', 37*6777b538SAndroid Build Coastguard Worker required=True) 38*6777b538SAndroid Build Coastguard Worker parser.add_argument('--make-bat', 39*6777b538SAndroid Build Coastguard Worker action='store_true', 40*6777b538SAndroid Build Coastguard Worker help='Generate a .bat file instead of a bash script') 41*6777b538SAndroid Build Coastguard Worker return parser.parse_args(args=args) 42*6777b538SAndroid Build Coastguard Worker 43*6777b538SAndroid Build Coastguard Worker 44*6777b538SAndroid Build Coastguard Workerdef _find_test_executables(args): 45*6777b538SAndroid Build Coastguard Worker exes = set() 46*6777b538SAndroid Build Coastguard Worker input_filepath = args.rust_test_executables 47*6777b538SAndroid Build Coastguard Worker with open(input_filepath) as f: 48*6777b538SAndroid Build Coastguard Worker for line in f: 49*6777b538SAndroid Build Coastguard Worker exe_name = line.strip() 50*6777b538SAndroid Build Coastguard Worker # Append ".exe" extension when *targeting* Windows, not when this 51*6777b538SAndroid Build Coastguard Worker # script is running on windows. We do that by using `args.make_bat` 52*6777b538SAndroid Build Coastguard Worker # as a signal. 53*6777b538SAndroid Build Coastguard Worker if exe_name in exes: 54*6777b538SAndroid Build Coastguard Worker raise ValueError( 55*6777b538SAndroid Build Coastguard Worker f'Duplicate entry "{exe_name}" in {input_filepath}') 56*6777b538SAndroid Build Coastguard Worker if args.make_bat: 57*6777b538SAndroid Build Coastguard Worker suffix = ".exe" 58*6777b538SAndroid Build Coastguard Worker else: 59*6777b538SAndroid Build Coastguard Worker suffix = "" 60*6777b538SAndroid Build Coastguard Worker exes.add(f'{exe_name}{suffix}') 61*6777b538SAndroid Build Coastguard Worker if not exes: 62*6777b538SAndroid Build Coastguard Worker raise ValueError(f'Unexpectedly empty file: {input_filepath}') 63*6777b538SAndroid Build Coastguard Worker exes = sorted(exes) # For stable results in unit tests. 64*6777b538SAndroid Build Coastguard Worker return exes 65*6777b538SAndroid Build Coastguard Worker 66*6777b538SAndroid Build Coastguard Worker 67*6777b538SAndroid Build Coastguard Workerdef _validate_if_test_executables_exist(exes): 68*6777b538SAndroid Build Coastguard Worker for exe in exes: 69*6777b538SAndroid Build Coastguard Worker if not os.path.isfile(exe): 70*6777b538SAndroid Build Coastguard Worker raise ValueError(f'File not found: {exe}') 71*6777b538SAndroid Build Coastguard Worker 72*6777b538SAndroid Build Coastguard Worker 73*6777b538SAndroid Build Coastguard Workerdef _generate_script(args, should_validate_if_exes_exist=True): 74*6777b538SAndroid Build Coastguard Worker THIS_DIR = os.path.abspath(os.path.dirname(__file__)) 75*6777b538SAndroid Build Coastguard Worker GEN_SCRIPT_DIR = os.path.dirname(args.script_path) 76*6777b538SAndroid Build Coastguard Worker 77*6777b538SAndroid Build Coastguard Worker # Path from the .bat or bash script to the test exes. 78*6777b538SAndroid Build Coastguard Worker exe_dir = os.path.relpath(args.exe_dir, start=GEN_SCRIPT_DIR) 79*6777b538SAndroid Build Coastguard Worker exe_dir = os.path.normpath(exe_dir) 80*6777b538SAndroid Build Coastguard Worker 81*6777b538SAndroid Build Coastguard Worker # Path from the .bat or bash script to the python main. 82*6777b538SAndroid Build Coastguard Worker main_dir = os.path.relpath(THIS_DIR, start=GEN_SCRIPT_DIR) 83*6777b538SAndroid Build Coastguard Worker main_dir = os.path.normpath(main_dir) 84*6777b538SAndroid Build Coastguard Worker 85*6777b538SAndroid Build Coastguard Worker exes = _find_test_executables(args) 86*6777b538SAndroid Build Coastguard Worker if should_validate_if_exes_exist: 87*6777b538SAndroid Build Coastguard Worker _validate_if_test_executables_exist(exes) 88*6777b538SAndroid Build Coastguard Worker 89*6777b538SAndroid Build Coastguard Worker if args.make_bat: 90*6777b538SAndroid Build Coastguard Worker res = '@echo off\n' 91*6777b538SAndroid Build Coastguard Worker res += f'vpython3 "%~dp0\\{main_dir}\\rust_main_program.py" ^\n' 92*6777b538SAndroid Build Coastguard Worker for exe in exes: 93*6777b538SAndroid Build Coastguard Worker res += f' "--rust-test-executable=%~dp0\\{exe_dir}\\{exe}" ^\n' 94*6777b538SAndroid Build Coastguard Worker res += ' %*' 95*6777b538SAndroid Build Coastguard Worker else: 96*6777b538SAndroid Build Coastguard Worker res = '#!/bin/bash\n' 97*6777b538SAndroid Build Coastguard Worker res += (f'env vpython3 ' 98*6777b538SAndroid Build Coastguard Worker f'"$(dirname $0)/{main_dir}/rust_main_program.py" \\\n') 99*6777b538SAndroid Build Coastguard Worker for exe in exes: 100*6777b538SAndroid Build Coastguard Worker res += ( 101*6777b538SAndroid Build Coastguard Worker f' ' 102*6777b538SAndroid Build Coastguard Worker f'"--rust-test-executable=$(dirname $0)/{exe_dir}/{exe}" \\\n') 103*6777b538SAndroid Build Coastguard Worker res += ' "$@"' 104*6777b538SAndroid Build Coastguard Worker return res 105*6777b538SAndroid Build Coastguard Worker 106*6777b538SAndroid Build Coastguard Worker 107*6777b538SAndroid Build Coastguard Workerdef _main(): 108*6777b538SAndroid Build Coastguard Worker args = _parse_args(sys.argv[1:]) 109*6777b538SAndroid Build Coastguard Worker 110*6777b538SAndroid Build Coastguard Worker # atomic_output will ensure we only write to the file on disk if what we 111*6777b538SAndroid Build Coastguard Worker # give to write() is different than what's currently on disk. 112*6777b538SAndroid Build Coastguard Worker with action_helpers.atomic_output(args.script_path) as f: 113*6777b538SAndroid Build Coastguard Worker f.write(_generate_script(args).encode()) 114*6777b538SAndroid Build Coastguard Worker 115*6777b538SAndroid Build Coastguard Worker # chmod a+x 116*6777b538SAndroid Build Coastguard Worker st = os.stat(args.script_path) 117*6777b538SAndroid Build Coastguard Worker if (not st.st_mode & stat.S_IXUSR) or (not st.st_mode & stat.S_IXGRP) or \ 118*6777b538SAndroid Build Coastguard Worker (not st.st_mode & stat.S_IXOTH): 119*6777b538SAndroid Build Coastguard Worker os.chmod(args.script_path, 120*6777b538SAndroid Build Coastguard Worker st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH) 121*6777b538SAndroid Build Coastguard Worker 122*6777b538SAndroid Build Coastguard Worker 123*6777b538SAndroid Build Coastguard Workerif __name__ == '__main__': 124*6777b538SAndroid Build Coastguard Worker _main() 125