#!/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 [....] # Run a program, can be an interactive shell. Use PATH. run.py -m [....] # Run a python module. Use PYTHONPATH. run.py -s .py [....] # Run a python script. run.py --vg [....] # 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