Skip to content

Commit

Permalink
[libc++] SSH: Properly handle test-executables that are not the first…
Browse files Browse the repository at this point in the history
… argument

If a ShTest has for example another command in front of the test
executable it wants to execute, ssh.py needs to properly translate
the path of that test executable to the executable on the remote host.
For example, running '%{exec} ! %t.exe', we can't assume that the
test-executable is the first argument after '%{exec}'.
  • Loading branch information
ldionne committed Apr 1, 2020
1 parent bb4a36e commit 0489d39
Showing 1 changed file with 29 additions and 29 deletions.
58 changes: 29 additions & 29 deletions libcxx/utils/ssh.py
Expand Up @@ -31,31 +31,34 @@ def main():
if len(remaining) < 2:
sys.stderr.write('Missing actual commands to run')
return 1
remaining = remaining[1:] # Skip the '--'

# HACK:
# If the first argument is a file that ends in `.tmp.exe`, assume it is
# the name of an executable generated by a test file. This allows us to
# do custom processing like codesigning the executable and changing its
# path when running on the remote host. It's possible for there to be no
# such executable, for example in the case of a .sh.cpp test.
exe = None
if os.path.exists(remaining[0]) and remaining[0].endswith('.tmp.exe'):
exe = remaining.pop(0)

# If there's an executable, do any necessary codesigning.
if exe and args.codesign_identity:
rc = subprocess.call(['xcrun', 'codesign', '-f', '-s', args.codesign_identity, exe], env={})
if rc != 0:
sys.stderr.write('Failed to codesign: {}'.format(exe))
return rc
commandLine = remaining[1:] # Skip the '--'

ssh = lambda command: ['ssh', '-oBatchMode=yes', args.host, command]
scp = lambda src, dst: ['scp', '-oBatchMode=yes', '-r', src, '{}:{}'.format(args.host, dst)]

# Create a temporary directory where the test will be run.
tmp = subprocess.check_output(ssh('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)
testExeOnRemote = lambda exe: posixpath.join(tmp, os.path.basename(exe))

try:
# Do any necessary codesigning of test-executables found in the command line.
if args.codesign_identity:
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: {}'.format(exe))
return rc

# Ensure the test dependencies exist and scp them to the temporary directory.
# Test dependencies can be either files or directories, so the `scp` command
# needs to use `-r`.
Expand All @@ -68,27 +71,24 @@ def main():
sys.stderr.write('Failed to copy dependency "{}" to remote host'.format(dep))
return rc

# If there's an executable, change its path to be in the temporary directory.
# We know it has been copied to the remote host when we handled the test
# dependencies above.
if exe:
exe = posixpath.join(tmp, os.path.basename(exe))

# If there's an executable, make sure it has 'execute' permissions on the
# remote host. The host that compiled the executable might not have a notion
# of 'executable' permissions.
if exe:
# Make sure all test-executables in the remote command line have 'execute'
# permissions on the remote host. The host that compiled the test-executable
# might not have a notion of 'executable' permissions.
for exe in map(testExeOnRemote, filter(isTestExe, commandLine)):
rc = subprocess.call(ssh('chmod +x {}'.format(exe)))
if rc != 0:
sys.stderr.write('Failed to chmod +x test-executable "{}" on the remote host'.format(exe))
return rc

# Execute the command through SSH in the temporary directory, with the
# correct environment.
# correct environment. We tweak the command line to run it on the remote
# host by transforming the path of test-executables to their path in the
# temporary directory, where we know they have been copied when we handled
# test dependencies above.
commands = [
'cd {}'.format(tmp),
'export {}'.format(' '.join(args.env)),
' '.join([exe] + remaining if exe else remaining)
' '.join(testExeOnRemote(x) if isTestExe(x) else x for x in commandLine)
]
rc = subprocess.call(ssh(' && '.join(commands)))
return rc
Expand Down

0 comments on commit 0489d39

Please sign in to comment.