blob: 06414f577f7a6179f8a12e7210137858197e963a [file] [log] [blame]
#!/usr/bin/env vpython3
# Copyright 2021 The Chromium Authors. All rights reserved.
# 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', 'android', 'gyp'))
from util import build_utils
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)
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))
exes.add(exe_name)
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_path))
def _generate_script(args, should_validate_if_exes_exist=True):
res = '#!/bin/bash\n'
script_dir = os.path.dirname(args.script_path)
res += 'SCRIPT_DIR=`dirname $0`\n'
exe_dir = os.path.relpath(args.exe_dir, start=script_dir)
exe_dir = os.path.normpath(exe_dir)
res += 'EXE_DIR="$SCRIPT_DIR/{}"\n'.format(exe_dir)
generator_script_dir = os.path.dirname(__file__)
lib_dir = os.path.relpath(generator_script_dir, script_dir)
lib_dir = os.path.normpath(lib_dir)
res += 'LIB_DIR="$SCRIPT_DIR/{}"\n'.format(lib_dir)
exes = _find_test_executables(args)
if should_validate_if_exes_exist:
_validate_if_test_executables_exist(exes)
res += 'env vpython3 "$LIB_DIR/rust_main_program.py" \\\n'
for exe in exes:
res += ' "--rust-test-executable=$EXE_DIR/{}" \\\n'.format(exe)
res += ' "$@"'
return res
def _main():
args = _parse_args(sys.argv[1:])
# AtomicOutput 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 build_utils.AtomicOutput(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()