from __future__ import print_function
import argparse
import glob
import os
import platform
import shlex
import shutil
import subprocess
import sys
import tempfile
def _parseArgs():
parser = argparse.ArgumentParser(description='USD test wrapper')
parser.add_argument('--stdout-redirect', type=str,
help='File to redirect stdout to')
parser.add_argument('--stderr-redirect', type=str,
help='File to redirect stderr to')
parser.add_argument('--diff-compare', default=[], type=str,
action='append',
help=('Compare output file with a file in the baseline-dir of the '
'same name'))
parser.add_argument('--files-exist', nargs='*',
help=('Check that a set of files exist.'))
parser.add_argument('--files-dont-exist', nargs='*',
help=('Check that a set of files exist.'))
parser.add_argument('--clean-output-paths', nargs='*',
help=('Path patterns to remove from the output files being diff\'d.'))
parser.add_argument('--post-command', type=str,
help=('Command line action to run after running COMMAND.'))
parser.add_argument('--pre-command', type=str,
help=('Command line action to run before running COMMAND.'))
parser.add_argument('--pre-command-stdout-redirect', type=str,
help=('File to redirect stdout to when running PRE_COMMAND.'))
parser.add_argument('--pre-command-stderr-redirect', type=str,
help=('File to redirect stderr to when running PRE_COMMAND.'))
parser.add_argument('--post-command-stdout-redirect', type=str,
help=('File to redirect stdout to when running POST_COMMAND.'))
parser.add_argument('--post-command-stderr-redirect', type=str,
help=('File to redirect stderr to when running POST_COMMAND.'))
parser.add_argument('--testenv-dir', type=str,
help='Testenv directory to copy into test run directory')
parser.add_argument('--baseline-dir',
help='Baseline directory to use with --diff-compare')
parser.add_argument('--expected-return-code', type=int, default=0,
help='Expected return code of this test.')
parser.add_argument('--env-var', dest='envVars', default=[], type=str,
action='append',
help=('Variable to set in the test environment, in KEY=VALUE form. '
'If "<PXR_TEST_DIR>" is in the value, it is replaced with the '
'absolute path of the temp directory the tests are run in'))
parser.add_argument('--pre-path', dest='prePaths', default=[], type=str,
action='append', help='Path to prepend to the PATH env var.')
parser.add_argument('--post-path', dest='postPaths', default=[], type=str,
action='append', help='Path to append to the PATH env var.')
parser.add_argument('--verbose', '-v', action='store_true',
help='Verbose output.')
parser.add_argument('cmd', metavar='CMD', type=str,
help='Test command to run')
return parser.parse_args()
def _resolvePath(baselineDir, fileName):
nonSpecific = os.path.join(baselineDir, 'non-specific')
if os.path.isdir(nonSpecific):
baselineDir = nonSpecific
return os.path.normpath(os.path.join(baselineDir, fileName))
def _stripPath(f, pathPattern):
import re
import platform
repl = ''
if platform.system() == 'Windows':
def _windowsReplacement(m):
return m.group(1).replace('\\', '/')
pathPattern = pathPattern.replace('\\', '/')
pathPattern = pathPattern.replace('/', '[/\\\\]')
pathPattern = pathPattern + '(\S*)'
repl = _windowsReplacement
with open(f, 'r+') as inputFile:
data = inputFile.read()
data = re.sub(pathPattern, repl, data)
inputFile.seek(0)
inputFile.write(data)
inputFile.truncate()
def _cleanOutput(pathPattern, fileName, verbose):
if verbose:
print("stripping path pattern {0} from file {1}".format(pathPattern,
fileName))
_stripPath(fileName, pathPattern)
return True
def _diff(fileName, baselineDir, verbose):
import platform
if platform.system() == 'Windows':
diff = 'fc.exe'
else:
diff = '/usr/bin/diff'
filesToDiff = glob.glob(fileName)
if not filesToDiff:
sys.stderr.write(
"Error: could not files matching {0} to diff".format(fileName))
return False
for fileToDiff in glob.glob(fileName):
cmd = [diff, _resolvePath(baselineDir, fileToDiff), fileToDiff]
if verbose:
print("diffing with {0}".format(cmd))
if subprocess.call(cmd) != 0:
return False
return True
def _copyTree(src, dest):
if not os.path.exists(dest):
os.makedirs(dest)
for item in os.listdir(src):
s = os.path.join(src, item)
d = os.path.join(dest, item)
if os.path.isdir(s):
shutil.copytree(s, d)
else:
shutil.copy2(s, d)
def _convertRetCode(retcode):
if retcode < 0:
return 128 + abs(retcode)
return retcode
def _getRedirects(out_redir, err_redir):
return (open(out_redir, 'w') if out_redir else None,
open(err_redir, 'w') if err_redir else None)
def _runCommand(raw_command, stdout_redir, stderr_redir, env,
expected_return_code):
cmd = shlex.split(raw_command)
fout, ferr = _getRedirects(stdout_redir, stderr_redir)
try:
print("cmd: %s" % (cmd, ))
retcode = _convertRetCode(subprocess.call(cmd, shell=False, env=env,
stdout=(fout or sys.stdout),
stderr=(ferr or sys.stderr)))
finally:
if fout:
fout.close()
if ferr:
ferr.close()
if retcode != expected_return_code:
if args.verbose:
sys.stderr.write(
"Error: return code {0} doesn't match "
"expected {1} (EXPECTED_RETURN_CODE).".format(retcode,
expected_return_code))
sys.exit(1)
if __name__ == '__main__':
args = _parseArgs()
if args.diff_compare and not args.baseline_dir:
sys.stderr.write("Error: --baseline-dir must be specified with "
"--diff-compare.")
sys.exit(1)
if args.clean_output_paths and not args.diff_compare:
sys.stderr.write("Error: --diff-compare must be specified with "
"--clean-output-paths.")
sys.exit(1)
testDir = tempfile.mkdtemp()
os.chdir(testDir)
if args.verbose:
print("chdir: {0}".format(testDir))
if args.testenv_dir and os.path.isdir(args.testenv_dir):
if args.verbose:
print("copying testenv dir: {0}".format(args.testenv_dir))
try:
_copyTree(args.testenv_dir, os.getcwd())
except Exception as e:
sys.stderr.write("Error: copying testenv directory: {0}".format(e))
sys.exit(1)
env = os.environ.copy()
for varStr in args.envVars:
try:
k, v = varStr.split('=', 1)
if k == 'PATH':
sys.stderr.write("Error: use --pre-path or --post-path to edit PATH.")
sys.exit(1)
v = v.replace('<PXR_TEST_DIR>', testDir)
env[k] = v
except IndexError:
sys.stderr.write("Error: envvar '{0}' not of the form "
"key=value".format(varStr))
sys.exit(1)
pathDelim = ';' if platform.system() == 'Windows' else ':'
paths = env.get('PATH', '').split(pathDelim)
paths = args.prePaths + paths + args.postPaths
env['PATH'] = pathDelim.join(paths)
env['ARCH_AVOID_JIT'] = '1'
if args.pre_command:
_runCommand(args.pre_command, args.pre_command_stdout_redirect,
args.pre_command_stderr_redirect, env, 0)
_runCommand(args.cmd, args.stdout_redirect, args.stderr_redirect,
env, args.expected_return_code)
if args.post_command:
_runCommand(args.post_command, args.post_command_stdout_redirect,
args.post_command_stderr_redirect, env, 0)
if args.clean_output_paths:
for path in args.clean_output_paths:
for diff in args.diff_compare:
_cleanOutput(path, diff, args.verbose)
if args.files_exist:
for f in args.files_exist:
if args.verbose:
print('checking if {0} exists.'.format(f))
if not os.path.exists(f):
sys.stderr.write('Error: {0} does not exist '
'(FILES_EXIST).'.format(f))
sys.exit(1)
if args.files_dont_exist:
for f in args.files_dont_exist:
if args.verbose:
print('checking if {0} does not exist.'.format(f))
if os.path.exists(f):
sys.stderr.write('Error: {0} does exist '
'(FILES_DONT_EXIST).'.format(f))
sys.exit(1)
if args.diff_compare:
for diff in args.diff_compare:
if not _diff(diff, args.baseline_dir, args.verbose):
sys.stderr.write('Error: diff for {0} failed '
'(DIFF_COMPARE).'.format(diff))
sys.exit(1)
sys.exit(0)