125 lines
4.5 KiB
Python
Executable File
125 lines
4.5 KiB
Python
Executable File
#!/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'))
|
|
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()
|
|
# TODO(https://crbug.com/1271215): Append ".exe" extension when
|
|
# *targeting* Windows. (The "targeting" part means that we can't
|
|
# just detect whether the build is *hosted* on Windows.)
|
|
if exe_name in exes:
|
|
raise ValueError("Duplicate entry ('{}') in {}".format(
|
|
exe_name, input_filepath))
|
|
if sys.platform == 'win32':
|
|
suffix = ".exe"
|
|
else:
|
|
suffix = ""
|
|
exes.add(f'{exe_name}{suffix}')
|
|
if not exes:
|
|
raise ValueError("Unexpectedly empty file: {}".format(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("File not found: {}".format(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 '
|
|
f'"$(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()
|