| #!/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. By default valgrind runs the 'memcheck' |
| tool. The valgrind tool and supression file can be overridden by setting the |
| 'VALGRIND_TOOL' and 'VALGRIND_SUPPRESSIONS' environment variables, |
| respectively. Additional options can be provided via the 'VALGRIND_OPTS' |
| environment variable. |
| """ |
| |
| 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', |
| '--num-callers=12', |
| '--error-exitcode=%d' % VALGRIND_ERROR, |
| '--quiet'] |
| opts.append('--tool=%s' % os.environ.get('VALGRIND_TOOL', 'memcheck')) |
| supp = os.environ.get('VALGRIND_SUPPRESSIONS', |
| '${CMAKE_SOURCE_DIR}/tests/valgrind.supp') |
| opts.append('--suppressions=%s' % supp) |
| if outfile: opts.append('--log-file=%s' % outfile) |
| opts.extend(os.environ.get('VALGRIND_OPTS', "").split()) |
| 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 |
| |