Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .bazelignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,6 @@ gazelle/examples/bzlmod_build_file_generation/bazel-bzlmod_build_file_generation
gazelle/examples/bzlmod_build_file_generation/bazel-out
gazelle/examples/bzlmod_build_file_generation/bazel-testlog
tests/integration/compile_pip_requirements/bazel-compile_pip_requirements
tests/integration/external_native_py_binary/bazel-external_native_py_binary
tests/integration/local_toolchains/bazel-local_toolchains
tests/integration/py_cc_toolchain_registered/bazel-py_cc_toolchain_registered
1 change: 1 addition & 0 deletions .bazelrc.deleted_packages
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ common --deleted_packages=gazelle/python/private
common --deleted_packages=tests/integration/compile_pip_requirements
common --deleted_packages=tests/integration/compile_pip_requirements_test_from_external_repo
common --deleted_packages=tests/integration/custom_commands
common --deleted_packages=tests/integration/external_native_py_binary
common --deleted_packages=tests/integration/local_toolchains
common --deleted_packages=tests/integration/pip_parse
common --deleted_packages=tests/integration/pip_parse/empty
Expand Down
32 changes: 29 additions & 3 deletions python/private/python_bootstrap_template.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,27 @@ import sys
import os
import subprocess
import uuid
import ast

# runfiles-relative path
# NOTE: The sentinel strings are split (e.g., "%stage2" + "_bootstrap%") so that
# the substitution logic won't replace them. This allows runtime detection of
# unsubstituted placeholders, which occurs when native py_binary is used in
# external repositories. In that case, we fall back to %main% which Bazel's
# native rule does substitute.
_STAGE2_BOOTSTRAP_SENTINEL = "%stage2" + "_bootstrap%"
STAGE2_BOOTSTRAP="%stage2_bootstrap%"
if STAGE2_BOOTSTRAP == _STAGE2_BOOTSTRAP_SENTINEL:
_MAIN_SENTINEL = "%main" + "%"
_main = "%main%"
if _main != _MAIN_SENTINEL and _main:
STAGE2_BOOTSTRAP = _main
else:
STAGE2_BOOTSTRAP = ""

if not STAGE2_BOOTSTRAP:
print("ERROR: %stage2_bootstrap% (or %main%) was not substituted.", file=sys.stderr)
sys.exit(1)

# runfiles-relative path to venv's python interpreter
# Empty string if a venv is not setup.
Expand All @@ -35,9 +53,17 @@ RECREATE_VENV_AT_RUNTIME="%recreate_venv_at_runtime%"
WORKSPACE_NAME = "%workspace_name%"

# Target-specific interpreter args.
INTERPRETER_ARGS = [
%interpreter_args%
]
# Sentinel split to detect unsubstituted placeholder (see STAGE2_BOOTSTRAP above).
_INTERPRETER_ARGS_SENTINEL = "%interpreter" + "_args%"
_INTERPRETER_ARGS_RAW = """%interpreter_args%""".strip()
if _INTERPRETER_ARGS_RAW and _INTERPRETER_ARGS_RAW != _INTERPRETER_ARGS_SENTINEL:
INTERPRETER_ARGS = [
ast.literal_eval(line.strip())
Comment thread
rickeylev marked this conversation as resolved.
Outdated
for line in _INTERPRETER_ARGS_RAW.splitlines()
if line.strip()
]
else:
INTERPRETER_ARGS = []

ADDITIONAL_INTERPRETER_ARGS = os.environ.get("RULES_PYTHON_ADDITIONAL_INTERPRETER_ARGS", "")

Expand Down
26 changes: 26 additions & 0 deletions python/private/stage1_bootstrap_template.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,22 @@ if [[ -n "${RULES_PYTHON_BOOTSTRAP_VERBOSE:-}" ]]; then
fi

# runfiles-relative path
# NOTE: The sentinel strings are split (e.g., "%stage2""_bootstrap%") so that
# the substitution logic won't replace them. This allows runtime detection of
# unsubstituted placeholders, which occurs when native py_binary is used in
# external repositories. In that case, we fall back to %main% which Bazel's
# native rule does substitute.
STAGE2_BOOTSTRAP_SENTINEL="%stage2""_bootstrap%"
MAIN_SENTINEL="%main""%"
Comment thread
rickeylev marked this conversation as resolved.
Outdated
STAGE2_BOOTSTRAP="%stage2_bootstrap%"
MAIN="%main%"
if [[ "$STAGE2_BOOTSTRAP" == "$STAGE2_BOOTSTRAP_SENTINEL" ]]; then
if [[ "$MAIN" != "$MAIN_SENTINEL" && -n "$MAIN" ]]; then
STAGE2_BOOTSTRAP="$MAIN"
else
STAGE2_BOOTSTRAP=""
fi
fi

# runfiles-relative path to python interpreter to use.
# This is the `bin/python3` path in the binary's venv.
Expand Down Expand Up @@ -35,6 +50,17 @@ VENV_REL_SITE_PACKAGES="%venv_rel_site_packages%"
declare -a INTERPRETER_ARGS_FROM_TARGET=(
%interpreter_args%
)
# Sentinel split to detect unsubstituted placeholder (see STAGE2_BOOTSTRAP above).
INTERPRETER_ARGS_SENTINEL="%interpreter""_args%"
if [[ "${#INTERPRETER_ARGS_FROM_TARGET[@]}" -eq 1 &&
"${INTERPRETER_ARGS_FROM_TARGET[0]}" == "$INTERPRETER_ARGS_SENTINEL" ]]; then
INTERPRETER_ARGS_FROM_TARGET=()
fi
Comment thread
rickeylev marked this conversation as resolved.
Outdated

if [[ -z "$STAGE2_BOOTSTRAP" ]]; then
echo >&2 "ERROR: %stage2_bootstrap% (or %main%) was not substituted."
exit 1
fi

if [[ "$IS_ZIPFILE" == "1" ]]; then
# NOTE: Macs have an old version of mktemp, so we must use only the
Expand Down
6 changes: 6 additions & 0 deletions tests/integration/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ rules_python_integration_test(
workspace_path = "compile_pip_requirements",
)

rules_python_integration_test(
name = "external_native_py_binary_workspace_test",
bzlmod = False,
workspace_path = "external_native_py_binary",
)

rules_python_integration_test(
name = "local_toolchains_test",
env = {
Expand Down
13 changes: 13 additions & 0 deletions tests/integration/external_native_py_binary/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package(default_visibility = ["//visibility:public"])

sh_test(
name = "external_native_py_binary_test",
srcs = ["external_native_py_binary_test.sh"],
data = [
"@bazel_tools//tools/bash/runfiles",
"@native_py_binary_repo//:external_native_py_binary",
],
env = {
"BIN_RLOCATION": "native_py_binary_repo/external_native_py_binary",
},
)
35 changes: 35 additions & 0 deletions tests/integration/external_native_py_binary/WORKSPACE
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
workspace(name = "external_native_py_binary")

load(
"@bazel_tools//tools/build_defs/repo:local.bzl",
"local_repository",
"new_local_repository",
)

local_repository(
name = "rules_python",
path = "../../..",
)

load("@rules_python//python:repositories.bzl", "py_repositories", "python_register_toolchains")

py_repositories()

python_register_toolchains(
name = "python_3_11",
python_version = "3.11",
)

new_local_repository(
name = "native_py_binary_repo",
path = "external_repo",
build_file_content = """
package(default_visibility = ["//visibility:public"])

py_binary(
name = "external_native_py_binary",
srcs = ["main.py"],
main = "main.py",
)
""",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -euo pipefail

# --- begin runfiles.bash initialization v3 ---
set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash
source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
source "$0.runfiles/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
{ echo >&2 "ERROR: cannot find $f"; exit 1; }
set -euo pipefail
# --- end runfiles.bash initialization v3 ---

bin=$(rlocation "$BIN_RLOCATION")
output="$("$bin")"
if [[ "$output" != "external-native-ok" ]]; then
echo >&2 "Expected 'external-native-ok' but got: $output"
exit 1
fi
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
print("external-native-ok")