blob: 45da99103dd7fadf947764526422793d5dd881db [file] [log] [blame]
#!/usr/bin/env python
##
## Licensed to the Apache Software Foundation (ASF) under one
## or more contributor license agreements. See the NOTICE file
## distributed with this work for additional information
## regarding copyright ownership. The ASF licenses this file
## to you under the Apache License, Version 2.0 (the
## "License"); you may not use this file except in compliance
## with the License. You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing,
## software distributed under the License is distributed on an
## "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
## KIND, either express or implied. See the License for the
## specific language governing permissions and limitations
## under the License
##
"""
Run a tool or test in a build tree with the correct PATH, PYTHONPATH, etc.
Run with no arguments for help.
"""
usage="""
Run a tool or test in a build tree with the correct PATH, PYTHONPATH, etc.
Usage:
run.py <program> [<arg>....] # Run a program, can be an interactive shell. Use PATH.
run.py -m <python-module> [<arg>....] # Run a python module. Use PYTHONPATH.
run.py -s <python-script>.py [<arg>....] # Run a python script.
run.py --vg <program> [<arg>....] # Run a program with valgrind if enabled. Use PATH.
run.py --sh # Print a shell script to set the run.py environment.
Valgrind can be enabled or disabled by the cmake 'USE_VALGRIND' option and the
environment variable 'USE_VALGRIND' (set to 'ON' or 'OFF'). The environment
variable takes precendence if set.
"""
import os, sys, runpy
from subprocess import Popen, PIPE
def dedup(l):
"""Remove duplicates from list l, keep first instance. Keep order of l."""
s = set()
return [i for i in l if i not in s and (s.add(i) or True)]
sys.path = dedup([
"${CMAKE_SOURCE_DIR}/python",
"${CMAKE_BINARY_DIR}/python",
"${CMAKE_SOURCE_DIR}/tests"
] + sys.path)
def getpath(env):
path = os.environ.get(env)
if path:
return path.split(os.pathsep)
return []
env_vars = {
'PYTHONPATH': os.pathsep.join(sys.path),
'PATH': os.pathsep.join(dedup(["${CMAKE_BINARY_DIR}",
os.path.join("${CMAKE_BINARY_DIR}", 'tests'),
os.path.join("${CMAKE_BINARY_DIR}", 'router'),
os.path.join("${CMAKE_SOURCE_DIR}", 'tools'),
os.path.join("${CMAKE_BINARY_DIR}", 'tools'),
os.path.join("${CMAKE_SOURCE_DIR}", 'bin')] +
getpath('PATH'))),
'MANPATH' : os.pathsep.join([os.path.join("${CMAKE_BINARY_DIR}",'doc','man')] +
getpath('MANPATH')),
'SOURCE_DIR': "${CMAKE_SOURCE_DIR}",
'BUILD_DIR': "${CMAKE_BINARY_DIR}",
'QPID_DISPATCH_HOME': "${CMAKE_SOURCE_DIR}",
'QPID_DISPATCH_LIB': "${CMAKE_BINARY_DIR}/src/${QPID_DISPATCH_LIB}"
}
os.environ.update(env_vars)
# Valgrind setup
valgrind_exe = "${VALGRIND_EXECUTABLE}"
def use_valgrind():
"""True if we should use valgrind"""
if not os.path.exists(valgrind_exe): return False
def on(str):
return str.lower() in ['on', 'yes', '1']
env = os.environ.get('USE_VALGRIND')
if env: return on(env)
return on("${USE_VALGRIND}")
def find_exe(program):
"""Find an executable in the system PATH"""
def is_exe(fpath):
return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
mydir, name = os.path.split(program)
if mydir:
if is_exe(program): return program
else:
for path in os.environ["PATH"].split(os.pathsep):
exe_file = os.path.join(path, program)
if is_exe(exe_file): return exe_file
return None
def is_binary_exe(program):
"""True if the program is a binary executable"""
if not program: return None
p = Popen(['file', '-bi', program], stdout=PIPE, stderr=PIPE)
return p.communicate()[0].startswith('application/x-executable')
VALGRIND_ERROR = 42 # magic number indicating valgrind found errors
def with_valgrind(args, outfile=None):
if use_valgrind() and is_binary_exe(find_exe(args[0])):
opts = ['--trace-children=yes',
# '--leak-check=full', way too noisy due to Python leaks
'--demangle=yes',
'--suppressions=${CMAKE_SOURCE_DIR}/tests/valgrind.supp',
'--num-callers=12',
'--error-exitcode=%d' % VALGRIND_ERROR,
'--quiet']
if outfile: opts.append('--log-file=%s' % outfile)
return ([valgrind_exe]+opts+args, VALGRIND_ERROR)
return (args, 0)
def run_path(file_path, run_name=None):
"""Wrapper for run path that falls back to exec python for python < 2.7"""
if hasattr(runpy, 'run_path'):
runpy.run_path(file_path, run_name=run_name)
else: # Python < 2.7
os.execvp(sys.executable, [sys.executable]+sys.argv)
if __name__ == "__main__":
error_prefix = ""
try:
if len(sys.argv) == 1:
print usage
elif sys.argv[1] == '-m':
sys.argv = sys.argv[2:]
error_prefix = "Run python module '%s': "%(sys.argv[0])
runpy.run_module(sys.argv[0], alter_sys=True, run_name="__main__")
elif sys.argv[1] == '-s':
sys.argv = sys.argv[2:]
error_prefix = "Run python script '%s':"%(sys.argv[0])
run_path(sys.argv[0], run_name="__main__")
elif sys.argv[1] == '--sh':
for name, value in env_vars.iteritems(): print "%s=%s"%(name, value)
print "export %s"%' '.join(env_vars.keys())
elif sys.argv[1] == '--vg':
args, ignore = with_valgrind(sys.argv[2:])
error_prefix = "Run executable '%s' with valgrind: "%(args[0])
os.execvp(args[0], args)
elif sys.argv[1].startswith('-'):
print usage
else:
args = sys.argv[1:]
error_prefix = "Run executable '%s': "%(args[0])
os.execvp(args[0], args)
except Exception, e:
print "%s%s: %s"%(error_prefix, type(e).__name__, e)
raise