diff --git a/libcxx/utils/libcxx/test/config.py b/libcxx/utils/libcxx/test/config.py --- a/libcxx/utils/libcxx/test/config.py +++ b/libcxx/utils/libcxx/test/config.py @@ -621,6 +621,7 @@ env_vars = ' '.join('%s=%s' % (k, pipes.quote(v)) for (k, v) in self.exec_env.items()) exec_args = [ '--execdir %T', + '--test-executable %t.exe', '--codesign_identity "{}"'.format(codesign_ident), '--env {}'.format(env_vars) ] diff --git a/libcxx/utils/run.py b/libcxx/utils/run.py --- a/libcxx/utils/run.py +++ b/libcxx/utils/run.py @@ -14,6 +14,7 @@ """ import argparse +import os import subprocess import sys @@ -22,18 +23,33 @@ parser = argparse.ArgumentParser() parser.add_argument('--execdir', type=str, required=True) parser.add_argument('--codesign_identity', type=str, required=False, default=None) + parser.add_argument('--test-executable', type=str, required=False, default=None, + help='The name of an executable generated by a test \ + file. Specifying it allows us to do custom \ + processing like codesigning test-executables. \ + It\'s also possible for there \ + to be no such executable, for example in \ + the case of a .sh.cpp test.') parser.add_argument('--env', type=str, nargs='*', required=False, default=dict()) parser.add_argument("command", nargs=argparse.ONE_OR_MORE) args = parser.parse_args() commandLine = args.command + def isTestExe(exe): + if not exe or not args.test_executable: + return False + try: + return os.path.samefile(exe, args.test_executable) + except FileNotFoundError: + return False + # Do any necessary codesigning. if args.codesign_identity: - exe = commandLine[0] - rc = subprocess.call(['xcrun', 'codesign', '-f', '-s', args.codesign_identity, exe], env={}) - if rc != 0: - sys.stderr.write('Failed to codesign: ' + exe) - return rc + for exe in filter(isTestExe, commandLine): + rc = subprocess.call(['xcrun', 'codesign', '-f', '-s', args.codesign_identity, exe], env={}) + if rc != 0: + sys.stderr.write('Failed to codesign: ' + exe) + return rc # Extract environment variables into a dictionary env = {k : v for (k, v) in map(lambda s: s.split('=', 1), args.env)} diff --git a/libcxx/utils/ssh.py b/libcxx/utils/ssh.py --- a/libcxx/utils/ssh.py +++ b/libcxx/utils/ssh.py @@ -44,6 +44,14 @@ parser.add_argument('--extra-ssh-args', type=str, required=False) parser.add_argument('--extra-scp-args', type=str, required=False) parser.add_argument('--codesign_identity', type=str, required=False, default=None) + parser.add_argument('--test-executable', type=str, required=False, default=None, + help='The name of an executable generated by a test \ + file. Specifying it allows us to do custom \ + processing like codesigning test-executables \ + and changing their path when running on \ + the remote host. It\'s also possible for there \ + to be no such executable, for example in \ + the case of a .sh.cpp test.') parser.add_argument('--env', type=str, nargs='*', required=False, default=dict()) parser.add_argument("command", nargs=argparse.ONE_OR_MORE) args = parser.parse_args() @@ -53,14 +61,14 @@ # That is effectively the value of %T on the remote host. tmp = subprocess.check_output(ssh(args, 'mktemp -d /tmp/libcxx.XXXXXXXXXX'), universal_newlines=True).strip() - # HACK: - # If an argument is a file that ends in `.tmp.exe`, assume it is the name - # of an executable generated by a test file. We call these test-executables - # below. This allows us to do custom processing like codesigning test-executables - # and changing their path when running on the remote host. It's also possible - # for there to be no such executable, for example in the case of a .sh.cpp - # test. - isTestExe = lambda exe: exe.endswith('.tmp.exe') and os.path.exists(exe) + def isTestExe(exe): + if not exe or not args.test_executable: + return False + try: + return os.path.samefile(exe, args.test_executable) + except FileNotFoundError: + return False + pathOnRemote = lambda file: posixpath.join(tmp, os.path.basename(file)) try: