1#!/usr/bin/env python
2#===----------------------------------------------------------------------===##
3#
4# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5# See https://llvm.org/LICENSE.txt for license information.
6# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7#
8#===----------------------------------------------------------------------===##
9
10"""run.py is a utility for running a program.
11
12It can perform code signing, forward arguments to the program, and return the
13program's error code.
14"""
15
16import argparse
17import os
18import platform
19import subprocess
20import sys
21
22
23def main():
24    parser = argparse.ArgumentParser()
25    parser.add_argument('--execdir', type=str, required=True)
26    parser.add_argument('--codesign_identity', type=str, required=False, default=None)
27    parser.add_argument('--env', type=str, nargs='*', required=False, default=dict())
28    parser.add_argument("command", nargs=argparse.ONE_OR_MORE)
29    args = parser.parse_args()
30    commandLine = args.command
31
32    # HACK:
33    # If an argument is a file that ends in `.tmp.exe`, assume it is the name
34    # of an executable generated by a test file. We call these test-executables
35    # below. This allows us to do custom processing like codesigning test-executables.
36    # It's also possible for there to be no such executable, for example in the case
37    # of a .sh.cpp test.
38    isTestExe = lambda exe: exe.endswith('.tmp.exe') and os.path.exists(exe)
39
40    # Do any necessary codesigning of test-executables found in the command line.
41    if args.codesign_identity:
42        for exe in filter(isTestExe, commandLine):
43            subprocess.check_call(['xcrun', 'codesign', '-f', '-s', args.codesign_identity, exe], env={})
44
45    # Extract environment variables into a dictionary
46    env = {k : v  for (k, v) in map(lambda s: s.split('=', 1), args.env)}
47    if platform.system() == 'Windows':
48        # Pass some extra variables through on Windows:
49        # COMSPEC is needed for running subprocesses via std::system().
50        if 'COMSPEC' in os.environ:
51            env['COMSPEC'] = os.environ.get('COMSPEC')
52        # TEMP is needed for placing temp files in a sensible directory.
53        if 'TEMP' in os.environ:
54            env['TEMP'] = os.environ.get('TEMP')
55
56    # Run the command line with the given environment in the execution directory.
57    return subprocess.call(commandLine, cwd=args.execdir, env=env, shell=False)
58
59
60if __name__ == '__main__':
61    exit(main())
62