99# runfiles-relative path
1010STAGE2_BOOTSTRAP=" %stage2_bootstrap%"
1111
12- # runfiles-relative path
12+ # runfiles-relative path to python interpreter to use
1313PYTHON_BINARY=' %python_binary%'
1414# The path that PYTHON_BINARY should symlink to.
1515# runfiles-relative path, absolute path, or single word.
16- # Only applicable for zip files.
16+ # Only applicable for zip files or when venv is recreated at runtime .
1717PYTHON_BINARY_ACTUAL=" %python_binary_actual%"
1818
1919# 0 or 1
2020IS_ZIPFILE=" %is_zipfile%"
21+ # 0 or 1
22+ RECREATE_VENV_AT_RUNTIME=" %recreate_venv_at_runtime%"
2123
2224if [[ " $IS_ZIPFILE " == " 1" ]]; then
2325 # NOTE: Macs have an old version of mktemp, so we must use only the
@@ -104,6 +106,7 @@ python_exe=$(find_python_interpreter $RUNFILES_DIR $PYTHON_BINARY)
104106# Zip files have to re-create the venv bin/python3 symlink because they
105107# don't contain it already.
106108if [[ " $IS_ZIPFILE " == " 1" ]]; then
109+ use_exec=0
107110 # It should always be under runfiles, but double check this. We don't
108111 # want to accidentally create symlinks elsewhere.
109112 if [[ " $python_exe " != $RUNFILES_DIR /* ]]; then
@@ -121,13 +124,60 @@ if [[ "$IS_ZIPFILE" == "1" ]]; then
121124 symlink_to=$( which $PYTHON_BINARY_ACTUAL )
122125 # Guard against trying to symlink to an empty value
123126 if [[ $? -ne 0 ]]; then
124- echo >&2 " ERROR: Python to use found on PATH: $PYTHON_BINARY_ACTUAL "
127+ echo >&2 " ERROR: Python to use not found on PATH: $PYTHON_BINARY_ACTUAL "
125128 exit 1
126129 fi
127130 fi
128131 # The bin/ directory may not exist if it is empty.
129132 mkdir -p " $( dirname $python_exe ) "
130133 ln -s " $symlink_to " " $python_exe "
134+ elif [[ " $RECREATE_VENV_AT_RUNTIME " == " 1" ]]; then
135+ runfiles_venv=" $RUNFILES_DIR /$( dirname $( dirname $PYTHON_BINARY ) ) "
136+ if [[ -n " $RULES_PYTHON_VENVS_ROOT " ]]; then
137+ use_exec=1
138+ # Use our runfiles path as a unique, reusable, location for the
139+ # binary-specific venv being created.
140+ venv=" $RULES_PYTHON_VENVS_ROOT /$( dirname $( dirname $PYTHON_BINARY ) ) "
141+ mkdir -p $RULES_PYTHON_VENVS_ROOT
142+ else
143+ # Re-exec'ing can't be used because we have to clean up the temporary
144+ # venv directory that is created.
145+ use_exec=0
146+ venv=$( mktemp -d)
147+ if [[ -n " $venv " && -z " ${RULES_PYTHON_BOOTSTRAP_VERBOSE:- } " ]]; then
148+ trap ' rm -fr "$venv"' EXIT
149+ fi
150+ fi
151+
152+ if [[ " $PYTHON_BINARY_ACTUAL " == /* ]]; then
153+ # An absolute path, i.e. platform runtime, e.g. /usr/bin/python3
154+ symlink_to=$PYTHON_BINARY_ACTUAL
155+ elif [[ " $PYTHON_BINARY_ACTUAL " == * /* ]]; then
156+ # A runfiles-relative path
157+ symlink_to=" $RUNFILES_DIR /$PYTHON_BINARY_ACTUAL "
158+ else
159+ # A plain word, e.g. "python3". Symlink to where PATH leads
160+ symlink_to=$( which $PYTHON_BINARY_ACTUAL )
161+ # Guard against trying to symlink to an empty value
162+ if [[ $? -ne 0 ]]; then
163+ echo >&2 " ERROR: Python to use not found on PATH: $PYTHON_BINARY_ACTUAL "
164+ exit 1
165+ fi
166+ fi
167+ mkdir -p " $venv /bin"
168+ # Match the basename; some tools, e.g. pyvenv key off the executable name
169+ python_exe=" $venv /bin/$( basename $PYTHON_BINARY_ACTUAL ) "
170+ if [[ ! -e " $python_exe " ]]; then
171+ ln -s " $symlink_to " " $python_exe "
172+ fi
173+ if [[ ! -e " $venv /pyvenv.cfg" ]]; then
174+ ln -s " $runfiles_venv /pyvenv.cfg" " $venv /pyvenv.cfg"
175+ fi
176+ if [[ ! -e " $venv /lib" ]]; then
177+ ln -s " $runfiles_venv /lib" " $venv /lib"
178+ fi
179+ else
180+ use_exec=1
131181fi
132182
133183# At this point, we should have a valid reference to the interpreter.
@@ -165,7 +215,6 @@ if [[ "$IS_ZIPFILE" == "1" ]]; then
165215 interpreter_args+=(" -XRULES_PYTHON_ZIP_DIR=$zip_dir " )
166216fi
167217
168-
169218export RUNFILES_DIR
170219
171220command=(
@@ -186,7 +235,7 @@ command=(
186235#
187236# However, when running a zip file, we need to clean up the workspace after the
188237# process finishes so control must return here.
189- if [[ " $IS_ZIPFILE " == " 1 " ]]; then
238+ if [[ " $use_exec " == " 0 " ]]; then
190239 " ${command[@]} "
191240 exit $?
192241else
0 commit comments