#!/usr/bin/python import os import re import sys PYTHON_BINARY = '%python_binary%' # Find a file in a given search path. def SearchPath(name): search_path = os.getenv('PATH', os.defpath).split(os.pathsep) for directory in search_path: if directory == '': continue path = os.path.join(directory, name) if os.path.exists(path): return path return None # Find the real Python binary if it's not a normal absolute path def FindPythonBinary(): if PYTHON_BINARY.startswith('//'): # Case 1: Path is a label. Not supported yet. raise AssertionError( 'Bazel does not support execution of Python interpreters via labels yet') elif PYTHON_BINARY.startswith('/'): # Case 2: Absolute path. return PYTHON_BINARY elif '/' in PYTHON_BINARY: # Case 3: Path is relative to current working directory. return os.path.join(os.getcwd(), PYTHON_BINARY) else: # Case 4: Path has to be looked up in the search path. return SearchPath(PYTHON_BINARY) def Main(): args = sys.argv[1:] new_env = {} # Follow symlinks, looking for my module space stub_filename = os.path.abspath(sys.argv[0]) while True: # Found it? module_space = stub_filename + '.runfiles' if os.path.isdir(module_space): break # Follow a symlink, try again? if os.path.islink(stub_filename): link = os.readlink(stub_filename) # Absolutize stub_filename = os.path.join(os.path.dirname(stub_filename), link) continue matchobj = re.match("(.*\.runfiles)/.*", os.path.abspath(sys.argv[0])) if matchobj: module_space = matchobj.group(1) break raise AssertionError('Cannot find .runfiles directory for %s' % sys.argv[0]) python_path_entries = [module_space] external_dir = os.path.join(module_space, 'external') if os.path.isdir(external_dir): external_entries = [os.path.join(external_dir, d) for d in os.listdir(external_dir)] repositories = [d for d in external_entries if os.path.isdir(d)] python_path_entries += repositories old_python_path = os.environ.get('PYTHONPATH') python_path = ':'.join(python_path_entries) if old_python_path: python_path += ':' + old_python_path new_env['PYTHONPATH'] = python_path # Now look for my main python source file. # The magic string percent-main-percent is replaced with the filename of the # main file of the Python binary in BazelPythonSemantics.java. main_filename = os.path.join(module_space, '%main%') assert os.path.exists(main_filename), \ 'Cannot exec() %r: file not found.' % main_filename assert os.access(main_filename, os.R_OK), \ 'Cannot exec() %r: file not readable.' % main_filename program = python_program = FindPythonBinary() if python_program is None: raise AssertionError('Could not find python binary: ' + PYTHON_BINARY) args = [python_program, main_filename] + args os.environ.update(new_env) try: sys.stdout.flush() os.execv(program, args) except EnvironmentError as e: # This exception occurs when os.execv() fails for some reason. if not getattr(e, 'filename', None): e.filename = program # Add info to error message raise if __name__ == '__main__': Main()