aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java
diff options
context:
space:
mode:
authorGravatar Philipp Wollermann <philwo@google.com>2015-08-24 17:52:31 +0000
committerGravatar Laszlo Csomor <laszlocsomor@google.com>2015-08-25 07:47:31 +0000
commit11bbdcb2bdee40c6cfca81b61aea63aee08ea804 (patch)
tree47d5cc2a51fda131d138c32f2eb1de226d152c46 /src/main/java
parent91ad93b9240d83165d16ec7d395bd16b7cdbb6d0 (diff)
Improve the Python launcher to be smarter and make less assumptions when looking for the .runfiles path and the Python interpreter binary.
-- MOS_MIGRATED_REVID=101380117
Diffstat (limited to 'src/main/java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/python/stub_template.txt98
1 files changed, 94 insertions, 4 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/stub_template.txt b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/stub_template.txt
index 3ec8385332..cbdde6869a 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/python/stub_template.txt
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/python/stub_template.txt
@@ -1,5 +1,95 @@
-#!/bin/bash -eu
+#!/usr/bin/python
-STUBPATH=$(%python_binary% -c "import os.path; print(os.path.realpath('$0'));")
-export PYTHONPATH=$STUBPATH.runfiles
-exec %python_binary% ${PYTHONPATH}/%main% "$@"
+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:
+ 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])
+
+ # 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
+
+ python_path = os.environ.get('PYTHONPATH')
+ if not python_path:
+ new_env['PYTHONPATH'] = module_space
+ else:
+ new_env['PYTHONPATH'] = '%s:%s' % (module_space, python_path)
+
+ 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, 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()