Skip to content

Commit

Permalink
feat: support Bazel 6 (#266)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexeagle committed Feb 21, 2024
1 parent 76e1908 commit ddc4f3b
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 20 deletions.
5 changes: 2 additions & 3 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,5 @@ jobs:
uses: bazel-contrib/.github/.github/workflows/bazel.yaml@e76b9e5a1d91256e06b097c4470a22263969600b
with:
folders: '[".", "e2e/smoke"]'
# TODO: make the root folder work with bzlmod
# MAYBE: allow usage from Bazel 6 as well
exclude: '[{"bazelversion": "6.4.0"}, {"folder": ".", "bzlmodEnabled": true}]'
# TODO(alex): switch the root folder to bzlmod
exclude: '[{"folder": ".", "bazelversion": "6.4.0"}, {"folder": ".", "bzlmodEnabled": true}]'
2 changes: 2 additions & 0 deletions e2e/smoke/.bazelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Under Bazel 7 or later, this flag is ignored as the PyRuntimeInfo gives this information.
common --@aspect_rules_py//py:interpreter_version=3.9.18
10 changes: 10 additions & 0 deletions py/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
load("@bazel_skylib//:bzl_library.bzl", "bzl_library")
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")

# For stardoc to reference the files
exports_files(["defs.bzl"])

# For Bazel 6.x compatibility, since
# PyRuntimeInfo shipped only with Bazel 7
# Users can set, e.g. --@aspect_rules_py//py:interpreter_version=3.9.18
string_flag(
name = "interpreter_version",
build_setting_default = "",
visibility = ["//visibility:public"],
)

bzl_library(
name = "repositories",
srcs = ["repositories.bzl"],
Expand Down
5 changes: 4 additions & 1 deletion py/private/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,10 @@ bzl_library(
name = "py_semantics",
srcs = ["py_semantics.bzl"],
visibility = ["//py:__subpackages__"],
deps = ["//py/private/toolchain:types"],
deps = [
"//py/private/toolchain:types",
"@bazel_skylib//rules:common_settings",
],
)

bzl_library(
Expand Down
12 changes: 8 additions & 4 deletions py/private/py_binary.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,15 @@ def _py_binary_rule_impl(ctx):
"{{ARG_PYTHON}}": to_rlocation_path(ctx, py_toolchain.python),
"{{ARG_VENV_NAME}}": ".{}.venv".format(ctx.attr.name),
"{{ARG_VENV_PYTHON_VERSION}}": "{}.{}.{}".format(
py_toolchain.toolchain.interpreter_version_info.major,
py_toolchain.toolchain.interpreter_version_info.minor,
py_toolchain.toolchain.interpreter_version_info.micro,
py_toolchain.interpreter_version_info.major,
py_toolchain.interpreter_version_info.minor,
py_toolchain.interpreter_version_info.micro,
),
"{{ARG_PTH_FILE}}": to_rlocation_path(ctx, site_packages_pth_file),
"{{ENTRYPOINT}}": to_rlocation_path(ctx, ctx.file.main),
"{{PYTHON_ENV}}": "\n".join(_dict_to_exports(env)).strip(),
"{{EXEC_PYTHON_BIN}}": "python{}".format(
py_toolchain.toolchain.interpreter_version_info.major,
py_toolchain.interpreter_version_info.major,
),
},
is_executable = True,
Expand Down Expand Up @@ -146,6 +146,10 @@ _attrs = dict({
"_runfiles_lib": attr.label(
default = "@bazel_tools//tools/bash/runfiles",
),
# NB: this is read by _resolve_toolchain in py_semantics.
"_interpreter_version_flag": attr.label(
default = "//py:interpreter_version",
),
})

_attrs.update(**_py_library.attrs)
Expand Down
43 changes: 42 additions & 1 deletion py/private/py_semantics.bzl
Original file line number Diff line number Diff line change
@@ -1,8 +1,32 @@
"""Functions to determine which Python toolchain to use"""

load("//py/private/toolchain:types.bzl", "PY_TOOLCHAIN")
load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")

_INTERPRETER_FLAGS = ["-B", "-I"]
_INTERPRETER_FLAGS = [
# -B Don't write .pyc files on import. See also PYTHONDONTWRITEBYTECODE.
"-B",
# -I Run Python in isolated mode. This also implies -E and -s.
# In isolated mode sys.path contains neither the script's directory nor the user's site-packages directory.
# All PYTHON* environment variables are ignored, too.
# Further restrictions may be imposed to prevent the user from injecting malicious code.
"-I",
]

_MUST_SET_INTERPRETER_VERSION_FLAG = """\
ERROR: Prior to Bazel 7.x, the python interpreter version must be explicitly provided.
For example in `.bazelrc` with Bazel 6.4, add
common --@aspect_rules_py//py:interpreter_version=3.9.18
Bazel 6.3 and earlier didn't handle the `common` verb for custom flags.
Repeat the flag to avoid discarding the analysis cache:
build --@aspect_rules_py//py:interpreter_version=3.9.18
fetch --@aspect_rules_py//py:interpreter_version=3.9.18
query --@aspect_rules_py//py:interpreter_version=3.9.18
"""

def _resolve_toolchain(ctx):
"""Resolves the Python toolchain to a simple struct.
Expand Down Expand Up @@ -36,10 +60,27 @@ def _resolve_toolchain(ctx):
files = depset([])
uses_interpreter_path = True

# Bazel 7 has this field on the PyRuntimeInfo
if "interpreter_version_info" in dir(py3_toolchain):
interpreter_version_info = py3_toolchain.interpreter_version_info
elif ctx.attr._interpreter_version_flag[BuildSettingInfo].value:
# Back-compat for Bazel 6.
# Same code as rules_python:
# https://github.com/bazelbuild/rules_python/blob/76f1c76f60ccb536d3b3e2c9f023d8063f40bcd5/python/repositories.bzl#L109
major, minor, micro = ctx.attr._interpreter_version_flag[BuildSettingInfo].value.split(".")
interpreter_version_info = struct(
major = major,
minor = minor,
micro = micro,
)
else:
fail(_MUST_SET_INTERPRETER_VERSION_FLAG)

return struct(
toolchain = py3_toolchain,
files = files,
python = interpreter,
interpreter_version_info = interpreter_version_info,
uses_interpreter_path = uses_interpreter_path,
flags = _INTERPRETER_FLAGS,
)
Expand Down
14 changes: 9 additions & 5 deletions py/private/py_unpacked_wheel.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ def _py_unpacked_wheel_impl(ctx):
py_toolchain.python,
"--python-version",
"{}.{}.{}".format(
py_toolchain.toolchain.interpreter_version_info.major,
py_toolchain.toolchain.interpreter_version_info.minor,
py_toolchain.toolchain.interpreter_version_info.micro,
py_toolchain.interpreter_version_info.major,
py_toolchain.interpreter_version_info.minor,
py_toolchain.interpreter_version_info.micro,
),
"--package-name",
ctx.attr.py_package_name,
Expand All @@ -44,8 +44,8 @@ def _py_unpacked_wheel_impl(ctx):
unpack_directory.basename,
"lib",
"python{}.{}".format(
py_toolchain.toolchain.interpreter_version_info.major,
py_toolchain.toolchain.interpreter_version_info.minor,
py_toolchain.interpreter_version_info.major,
py_toolchain.interpreter_version_info.minor,
),
"site-packages",
)
Expand Down Expand Up @@ -74,6 +74,10 @@ _attrs = {
"py_package_name": attr.string(
mandatory = True,
),
# NB: this is read by _resolve_toolchain in py_semantics.
"_interpreter_version_flag": attr.label(
default = "//py:interpreter_version",
),
}

py_unpacked_wheel = rule(
Expand Down
12 changes: 8 additions & 4 deletions py/private/py_venv.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@ def _py_venv_rule_imp(ctx):
"{{ARG_PYTHON}}": to_rlocation_path(ctx, py_toolchain.python),
"{{ARG_VENV_LOCATION}}": paths.join(ctx.attr.location, ctx.attr.venv_name),
"{{ARG_VENV_PYTHON_VERSION}}": "{}.{}.{}".format(
py_toolchain.toolchain.interpreter_version_info.major,
py_toolchain.toolchain.interpreter_version_info.minor,
py_toolchain.toolchain.interpreter_version_info.micro,
py_toolchain.interpreter_version_info.major,
py_toolchain.interpreter_version_info.minor,
py_toolchain.interpreter_version_info.micro,
),
"{{ARG_PTH_FILE}}": to_rlocation_path(ctx, site_packages_pth_file),
"{{EXEC_PYTHON_BIN}}": "python{}".format(
py_toolchain.toolchain.interpreter_version_info.major,
py_toolchain.interpreter_version_info.major,
),
},
is_executable = True,
Expand Down Expand Up @@ -115,6 +115,10 @@ _py_venv = rule(
"_runfiles_lib": attr.label(
default = "@bazel_tools//tools/bash/runfiles",
),
# NB: this is read by _resolve_toolchain in py_semantics.
"_interpreter_version_flag": attr.label(
default = "//py:interpreter_version",
),
},
toolchains = [
SH_TOOLCHAIN,
Expand Down
3 changes: 1 addition & 2 deletions py/private/toolchain/autodetecting.bzl
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# buildifier: disable=module-docstring
load("//py/private:py_semantics.bzl", _py_semantics = "semantics")

def _autodetecting_py_wrapper_impl(rctx):
which_python = rctx.which("python3")
Expand All @@ -8,7 +7,7 @@ def _autodetecting_py_wrapper_impl(rctx):

# Check if `which_python` ends up being the final binary, or it's actually a wrapper itself.
exec_result = rctx.execute(
[which_python] + _py_semantics.interpreter_flags + ["-c", "import sys; import os; print(os.path.realpath(sys.executable))"],
[which_python] + ["-B", "-I", "-c", "import sys; import os; print(os.path.realpath(sys.executable))"],
)

if exec_result.return_code == 0:
Expand Down

0 comments on commit ddc4f3b

Please sign in to comment.