1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
#!/usr/bin/python
import os
import re
import sys
import subprocess
# Return True if running on Windows
def IsWindows():
return os.name == 'nt'
PYTHON_BINARY = '%python_binary%'
if IsWindows() and not PYTHON_BINARY.endswith('.exe'):
PYTHON_BINARY = PYTHON_BINARY + '.exe'
# 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.isfile(path) and os.access(path, os.X_OK):
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 CreatePythonPathEntries(python_imports, module_space):
parts = python_imports.split(':');
return [module_space] + ["%s/%s" % (module_space, path) for path in parts]
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
runfiles_pattern = "(.*\.runfiles)/.*"
if IsWindows():
runfiles_pattern = "(.*\.runfiles)\\.*"
matchobj = re.match(runfiles_pattern, 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_imports = '%imports%'
module_space_with_workspace_name = module_space
if '%workspace_name%' != '':
module_space_with_workspace_name = os.path.join(module_space, '%workspace_name%')
python_path_entries = CreatePythonPathEntries(
python_imports, module_space_with_workspace_name)
external_dir = os.path.join(module_space_with_workspace_name, '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')
separator = ':'
if IsWindows():
separator = ';'
python_path = separator.join(python_path_entries)
if old_python_path:
python_path += separator + 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()
exit(subprocess.call(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()
|