From c5d94a301d5092efc1de9fa97462c3a3f9f52c5a Mon Sep 17 00:00:00 2001 From: Malte Poll <1780588+malt3@users.noreply.github.com> Date: Wed, 6 Aug 2025 07:33:36 +0200 Subject: [PATCH] use "command -v" to find interpreter in $PATH In some environments, `which` doesn't work correctly under Bazel, while `command -v` does. I think the difference is that `command` is a shell builtin (and POSIX compliant), whereas `which` is not: ``` $ sh -c 'builtin command -v python3' /usr/bin/python3 $ sh -c 'builtin which python3' sh: line 1: builtin: which: not a shell builtin ``` While `command -v` performs fewer checks under the hood, it is more portable. --- CHANGELOG.md | 2 ++ python/private/runtime_env_toolchain_interpreter.sh | 12 +++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 422e399026..08991c6107 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -101,6 +101,8 @@ END_UNRELEASED_TEMPLATE `# gazelle:python_resolve_sibling_imports true` * (pypi) Show overridden index URL of packages when downloading metadata have failed. ([#2985](https://github.com/bazel-contrib/rules_python/issues/2985)). +* (toolchains) use "command -v" to find interpreter in `$PATH` + ([#3150](https://github.com/bazel-contrib/rules_python/pull/3150)). {#v0-0-0-added} ### Added diff --git a/python/private/runtime_env_toolchain_interpreter.sh b/python/private/runtime_env_toolchain_interpreter.sh index dd4d648d12..c78cfe1a9b 100755 --- a/python/private/runtime_env_toolchain_interpreter.sh +++ b/python/private/runtime_env_toolchain_interpreter.sh @@ -17,16 +17,14 @@ die() { exit 1 } -# We use `which` to locate the Python interpreter command on PATH. `command -v` -# is another option, but it doesn't check whether the file it finds has the -# executable bit. +# We use `command -v` to locate the Python interpreter command on PATH. # # A tricky situation happens when this wrapper is invoked as part of running a # tool, e.g. passing a py_binary target to `ctx.actions.run()`. Bazel will unset # the PATH variable. Then the shell will see there's no PATH and initialize its -# own, sometimes without exporting it. This causes `which` to fail and this +# own, sometimes without exporting it. This causes `command -v` to fail and this # script to think there's no Python interpreter installed. To avoid this we -# explicitly pass PATH to each `which` invocation. We can't just export PATH +# explicitly pass PATH to each `command -v` invocation. We can't just export PATH # because that would modify the environment seen by the final user Python # program. # @@ -37,9 +35,9 @@ die() { # https://github.com/bazelbuild/bazel/issues/8415 # Try the "python3" command name first, then fall back on "python". -PYTHON_BIN="$(PATH="$PATH" which python3 2> /dev/null)" +PYTHON_BIN="$(PATH="$PATH" command -v python3 2> /dev/null)" if [ -z "${PYTHON_BIN:-}" ]; then - PYTHON_BIN="$(PATH="$PATH" which python 2>/dev/null)" + PYTHON_BIN="$(PATH="$PATH" command -v python 2>/dev/null)" fi if [ -z "${PYTHON_BIN:-}" ]; then die "Neither 'python3' nor 'python' were found on the target \