diff --git a/news/4386.fixed.md b/news/4386.fixed.md new file mode 100644 index 0000000000..877e3e5e0b --- /dev/null +++ b/news/4386.fixed.md @@ -0,0 +1,3 @@ +(rules) Fixed stage 1 bootstrap script failing when the executable path, +runfiles root, or `RULES_PYTHON_EXTRACT_ROOT` contains spaces +([#4386](https://github.com/bazel-contrib/rules_python/pull/4386)). diff --git a/python/private/stage1_bootstrap_template.sh b/python/private/stage1_bootstrap_template.sh index ef098127fd..7f4ba8e2eb 100644 --- a/python/private/stage1_bootstrap_template.sh +++ b/python/private/stage1_bootstrap_template.sh @@ -123,12 +123,12 @@ else if [[ ! -L "$stub_filename" ]]; then break fi - stub_filename=$(readlink $stub_filename) + stub_filename=$(readlink "$stub_filename") done echo >&2 "Unable to find runfiles directory for $1" exit 1 } - RUNFILES_DIR=$(find_runfiles_root $0) + RUNFILES_DIR=$(find_runfiles_root "$0") fi if [[ -n "$RULES_PYTHON_TESTING_TELL_RUNFILES_ROOT" ]]; then @@ -150,7 +150,7 @@ function find_python_interpreter() { fi } -python_exe=$(find_python_interpreter $RUNFILES_DIR $PYTHON_BINARY) +python_exe=$(find_python_interpreter "$RUNFILES_DIR" "$PYTHON_BINARY") # Zip files have to re-create the venv bin/python3 symlink because they # don't contain it already. @@ -159,7 +159,7 @@ if [[ "$IS_ZIPFILE" == "1" ]]; then use_exec=1 # It should always be under runfiles, but double check this. We don't # want to accidentally create symlinks elsewhere. - if [[ "$python_exe" != $RUNFILES_DIR/* ]]; then + if [[ "$python_exe" != "$RUNFILES_DIR"/* ]]; then echo >&2 "ERROR: Program's venv binary not under runfiles: $python_exe" exit 1 fi @@ -179,15 +179,15 @@ if [[ "$IS_ZIPFILE" == "1" ]]; then fi fi # The bin/ directory may not exist if it is empty. - mkdir -p "$(dirname $python_exe)" + mkdir -p "$(dirname "$python_exe")" _symlink "$symlink_to" "$python_exe" elif [[ "$RECREATE_VENV_AT_RUNTIME" == "1" ]]; then if [[ -n "$RULES_PYTHON_EXTRACT_ROOT" ]]; then use_exec=1 # Use our runfiles path as a unique, reusable, location for the # binary-specific venv being created. - venv="$RULES_PYTHON_EXTRACT_ROOT/$(dirname $(dirname $PYTHON_BINARY))" - mkdir -p $RULES_PYTHON_EXTRACT_ROOT + venv="$RULES_PYTHON_EXTRACT_ROOT/$(dirname "$(dirname "$PYTHON_BINARY")")" + mkdir -p "$RULES_PYTHON_EXTRACT_ROOT" else # Re-exec'ing can't be used because we have to clean up the temporary # venv directory that is created. @@ -199,7 +199,7 @@ elif [[ "$RECREATE_VENV_AT_RUNTIME" == "1" ]]; then fi # Match the basename; some tools, e.g. pyvenv key off the executable name - python_exe="$venv/bin/$(basename $PYTHON_BINARY_ACTUAL)" + python_exe="$venv/bin/$(basename "$PYTHON_BINARY_ACTUAL")" if [[ ! -e "$python_exe" ]]; then if [[ "$PYTHON_BINARY_ACTUAL" == /* ]]; then @@ -218,7 +218,7 @@ elif [[ "$RECREATE_VENV_AT_RUNTIME" == "1" ]]; then fi fi - runfiles_venv="$RUNFILES_DIR/$(dirname $(dirname $PYTHON_BINARY))" + runfiles_venv="$RUNFILES_DIR/$(dirname "$(dirname "$PYTHON_BINARY")")" # When RESOLVE_PYTHON_BINARY_AT_RUNTIME is true, it means the toolchain # has thrown two complications at us: # 1. The build-time assumption of the Python version may not match the @@ -256,7 +256,7 @@ EOF _symlink "$python_exe_actual" "$python_exe" if [[ ! -e "$venv_site_packages" ]]; then - mkdir -p $(dirname $venv_site_packages) + mkdir -p "$(dirname "$venv_site_packages")" _symlink "$runfiles_venv_site_packages" "$venv_site_packages" fi fi @@ -273,7 +273,7 @@ fi if [[ ! -x "$python_exe" ]]; then if [[ ! -e "$python_exe" ]]; then echo >&2 "ERROR: Python interpreter not found: $python_exe" - ls -l $python_exe >&2 + ls -l "$python_exe" >&2 exit 1 elif [[ ! -x "$python_exe" ]]; then echo >&2 "ERROR: Python interpreter not executable: $python_exe" diff --git a/tests/bootstrap_impls/run_binary_find_runfiles_test.sh b/tests/bootstrap_impls/run_binary_find_runfiles_test.sh index a6c1b565db..a5deea8a44 100755 --- a/tests/bootstrap_impls/run_binary_find_runfiles_test.sh +++ b/tests/bootstrap_impls/run_binary_find_runfiles_test.sh @@ -30,14 +30,20 @@ if [[ -z "$bin" ]]; then exit 1 fi -bin_link_layer_1=$TEST_TMPDIR/link1 +bin_link_layer_1="$TEST_TMPDIR/link with spaces 1" ln -s "$bin" "$bin_link_layer_1" -bin_link_layer_2=$TEST_TMPDIR/link2 +bin_link_layer_2="$TEST_TMPDIR/link with spaces 2" ln -s "$bin_link_layer_1" "$bin_link_layer_2" -result=$(RUNFILES_DIR='' RUNFILES_MANIFEST_FILE='' $bin) -result_link_layer_1=$(RUNFILES_DIR='' RUNFILES_MANIFEST_FILE='' $bin_link_layer_1) -result_link_layer_2=$(RUNFILES_DIR='' RUNFILES_MANIFEST_FILE='' $bin_link_layer_2) +space_dir="$TEST_TMPDIR/dir with spaces" +mkdir -p "$space_dir" +runfiles_with_spaces="$space_dir/test.runfiles" +ln -s "${bin%.runfiles*}.runfiles" "$runfiles_with_spaces" + +result=$(RUNFILES_DIR='' RUNFILES_MANIFEST_FILE='' "$bin") +result_link_layer_1=$(RUNFILES_DIR='' RUNFILES_MANIFEST_FILE='' "$bin_link_layer_1") +result_link_layer_2=$(RUNFILES_DIR='' RUNFILES_MANIFEST_FILE='' "$bin_link_layer_2") +result_space_runfiles=$(RUNFILES_DIR="$runfiles_with_spaces" RUNFILES_MANIFEST_FILE='' "$bin_link_layer_2") if [[ "$result" != "$result_link_layer_1" ]]; then echo "Output from test does not match output when invoked via a link;" @@ -55,5 +61,10 @@ if [[ "$result" != "$result_link_layer_2" ]]; then echo "$result_link_layer_2" exit 1 fi +if ! grep -q "^Hello$" <<<"$result_space_runfiles"; then + echo "Expected output when invoked with RUNFILES_DIR containing spaces, got:" + echo "$result_space_runfiles" + exit 1 +fi exit 0 diff --git a/tests/bootstrap_impls/run_binary_venvs_use_declare_symlink_no_test.sh b/tests/bootstrap_impls/run_binary_venvs_use_declare_symlink_no_test.sh index d4840116f9..cfd5aa9be2 100755 --- a/tests/bootstrap_impls/run_binary_venvs_use_declare_symlink_no_test.sh +++ b/tests/bootstrap_impls/run_binary_venvs_use_declare_symlink_no_test.sh @@ -48,8 +48,8 @@ function expect_match() { expect_match "sys.executable:.*tmp.*python3" "$actual" # Now test that using a custom location for the bootstrap files works -venvs_root=$(mktemp -d) -actual=$(RULES_PYTHON_EXTRACT_ROOT=$venvs_root $bin) +venvs_root=$(mktemp -d "$TEST_TMPDIR/venvs root.XXXXXX") +actual=$(RULES_PYTHON_EXTRACT_ROOT="$venvs_root" "$bin") expect_match "sys.executable:.*$venvs_root" "$actual" # Exit if any of the expects failed