| #!/usr/bin/env vpython3 | |
| # Copyright 2021 The Chromium Authors | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| import argparse | |
| import os | |
| import stat | |
| import sys | |
| sys.path.append( | |
| os.path.join( | |
| os.path.dirname(__file__), os.pardir, os.pardir, os.pardir, 'build' | |
| ) | |
| ) | |
| # //build imports. | |
| import action_helpers | |
| def _parse_args(args): | |
| description = ( | |
| 'Generator of bash scripts that can invoke the Python ' | |
| 'library for running Rust unit tests with support for ' | |
| 'Chromium test filters, sharding, and test output.' | |
| ) | |
| parser = argparse.ArgumentParser(description=description) | |
| parser.add_argument( | |
| '--script-path', | |
| dest='script_path', | |
| help='Where to write the bash script.', | |
| metavar='FILEPATH', | |
| required=True, | |
| ) | |
| parser.add_argument( | |
| '--exe-dir', | |
| dest='exe_dir', | |
| help='Directory where the wrapped executables are', | |
| metavar='PATH', | |
| required=True, | |
| ) | |
| parser.add_argument( | |
| '--rust-test-executables', | |
| dest='rust_test_executables', | |
| help='File listing one or more executables to wrap. ' | |
| '(basenames - no .exe extension or directory)', | |
| metavar='FILEPATH', | |
| required=True, | |
| ) | |
| parser.add_argument( | |
| '--make-bat', | |
| action='store_true', | |
| help='Generate a .bat file instead of a bash script', | |
| ) | |
| return parser.parse_args(args=args) | |
| def _find_test_executables(args): | |
| exes = set() | |
| input_filepath = args.rust_test_executables | |
| with open(input_filepath) as f: | |
| for line in f: | |
| exe_name = line.strip() | |
| # Append ".exe" extension when *targeting* Windows, not when this | |
| # script is running on windows. We do that by using `args.make_bat` | |
| # as a signal. | |
| if exe_name in exes: | |
| raise ValueError( | |
| f'Duplicate entry "{exe_name}" in {input_filepath}' | |
| ) | |
| if args.make_bat: | |
| suffix = '.exe' | |
| else: | |
| suffix = '' | |
| exes.add(f'{exe_name}{suffix}') | |
| if not exes: | |
| raise ValueError(f'Unexpectedly empty file: {input_filepath}') | |
| exes = sorted(exes) # For stable results in unit tests. | |
| return exes | |
| def _validate_if_test_executables_exist(exes): | |
| for exe in exes: | |
| if not os.path.isfile(exe): | |
| raise ValueError(f'File not found: {exe}') | |
| def _generate_script(args, should_validate_if_exes_exist=True): | |
| THIS_DIR = os.path.abspath(os.path.dirname(__file__)) | |
| GEN_SCRIPT_DIR = os.path.dirname(args.script_path) | |
| # Path from the .bat or bash script to the test exes. | |
| exe_dir = os.path.relpath(args.exe_dir, start=GEN_SCRIPT_DIR) | |
| exe_dir = os.path.normpath(exe_dir) | |
| # Path from the .bat or bash script to the python main. | |
| main_dir = os.path.relpath(THIS_DIR, start=GEN_SCRIPT_DIR) | |
| main_dir = os.path.normpath(main_dir) | |
| exes = _find_test_executables(args) | |
| if should_validate_if_exes_exist: | |
| _validate_if_test_executables_exist(exes) | |
| if args.make_bat: | |
| res = '@echo off\n' | |
| res += f'vpython3 "%~dp0\\{main_dir}\\rust_main_program.py" ^\n' | |
| for exe in exes: | |
| res += f' "--rust-test-executable=%~dp0\\{exe_dir}\\{exe}" ^\n' | |
| res += ' %*' | |
| else: | |
| res = '#!/bin/bash\n' | |
| res += ( | |
| f'env vpython3 "$(dirname $0)/{main_dir}/rust_main_program.py" \\\n' | |
| ) | |
| for exe in exes: | |
| res += ( | |
| f' ' | |
| f'"--rust-test-executable=$(dirname $0)/{exe_dir}/{exe}" \\\n' | |
| ) | |
| res += ' "$@"' | |
| return res | |
| def _main(): | |
| args = _parse_args(sys.argv[1:]) | |
| # atomic_output will ensure we only write to the file on disk if what we | |
| # give to write() is different than what's currently on disk. | |
| with action_helpers.atomic_output(args.script_path) as f: | |
| f.write(_generate_script(args).encode()) | |
| # chmod a+x | |
| st = os.stat(args.script_path) | |
| if ( | |
| (not st.st_mode & stat.S_IXUSR) | |
| or (not st.st_mode & stat.S_IXGRP) | |
| or (not st.st_mode & stat.S_IXOTH) | |
| ): | |
| os.chmod( | |
| args.script_path, | |
| st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH, | |
| ) | |
| if __name__ == '__main__': | |
| _main() |