blob: 9c8134ff40e310a67f4425616791685169267b68 [file] [log] [blame]
# Copyright 2024 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Run a py_binary with altered config settings in an sh_test.
This facilitates verify running binaries with different configuration settings
without the overhead of a bazel-in-bazel integration test.
"""
load("@rules_shell//shell:sh_test.bzl", "sh_test")
load("//python/private:attr_builders.bzl", "attrb") # buildifier: disable=bzl-visibility
load("//python/private:py_binary_macro.bzl", "py_binary_macro") # buildifier: disable=bzl-visibility
load("//python/private:py_binary_rule.bzl", "create_py_binary_rule_builder") # buildifier: disable=bzl-visibility
load("//python/private:py_test_macro.bzl", "py_test_macro") # buildifier: disable=bzl-visibility
load("//python/private:py_test_rule.bzl", "create_py_test_rule_builder") # buildifier: disable=bzl-visibility
load("//python/private:toolchain_types.bzl", "TARGET_TOOLCHAIN_TYPE") # buildifier: disable=bzl-visibility
load("//tests/support:support.bzl", "VISIBLE_FOR_TESTING")
def _perform_transition_impl(input_settings, attr, base_impl):
settings = {k: input_settings[k] for k in _RECONFIG_INHERITED_OUTPUTS if k in input_settings}
settings.update(base_impl(input_settings, attr))
settings[VISIBLE_FOR_TESTING] = True
settings["//command_line_option:build_python_zip"] = attr.build_python_zip
if attr.bootstrap_impl:
settings["//python/config_settings:bootstrap_impl"] = attr.bootstrap_impl
if attr.extra_toolchains:
settings["//command_line_option:extra_toolchains"] = attr.extra_toolchains
if attr.python_src:
settings["//python/bin:python_src"] = attr.python_src
if attr.venvs_use_declare_symlink:
settings["//python/config_settings:venvs_use_declare_symlink"] = attr.venvs_use_declare_symlink
if attr.venvs_site_packages:
settings["//python/config_settings:venvs_site_packages"] = attr.venvs_site_packages
return settings
_RECONFIG_INPUTS = [
"//python/config_settings:bootstrap_impl",
"//python/bin:python_src",
"//command_line_option:extra_toolchains",
"//python/config_settings:venvs_use_declare_symlink",
"//python/config_settings:venvs_site_packages",
]
_RECONFIG_OUTPUTS = _RECONFIG_INPUTS + [
"//command_line_option:build_python_zip",
VISIBLE_FOR_TESTING,
]
_RECONFIG_INHERITED_OUTPUTS = [v for v in _RECONFIG_OUTPUTS if v in _RECONFIG_INPUTS]
_RECONFIG_ATTRS = {
"bootstrap_impl": attrb.String(),
"build_python_zip": attrb.String(default = "auto"),
"extra_toolchains": attrb.StringList(
doc = """
Value for the --extra_toolchains flag.
NOTE: You'll likely have to also specify //tests/support/cc_toolchains:all (or some CC toolchain)
to make the RBE presubmits happy, which disable auto-detection of a CC
toolchain.
""",
),
"python_src": attrb.Label(),
"venvs_site_packages": attrb.String(),
"venvs_use_declare_symlink": attrb.String(),
}
def _create_reconfig_rule(builder):
builder.attrs.update(_RECONFIG_ATTRS)
base_cfg_impl = builder.cfg.implementation()
builder.cfg.set_implementation(lambda *args: _perform_transition_impl(base_impl = base_cfg_impl, *args))
builder.cfg.update_inputs(_RECONFIG_INPUTS)
builder.cfg.update_outputs(_RECONFIG_OUTPUTS)
return builder.build()
_py_reconfig_binary = _create_reconfig_rule(create_py_binary_rule_builder())
_py_reconfig_test = _create_reconfig_rule(create_py_test_rule_builder())
def py_reconfig_test(**kwargs):
"""Create a py_test with customized build settings for testing.
Args:
**kwargs: kwargs to pass along to _py_reconfig_test.
"""
py_test_macro(_py_reconfig_test, **kwargs)
def py_reconfig_binary(**kwargs):
py_binary_macro(_py_reconfig_binary, **kwargs)
def sh_py_run_test(*, name, sh_src, py_src, **kwargs):
"""Run a py_binary within a sh_test.
Args:
name: name of the sh_test and base name of inner targets.
sh_src: .sh file to run as a test
py_src: .py file for the py_binary
**kwargs: additional kwargs passed onto py_binary and/or sh_test
"""
bin_name = "_{}_bin".format(name)
sh_test(
name = name,
srcs = [sh_src],
data = [bin_name],
deps = [
"@bazel_tools//tools/bash/runfiles",
],
env = {
"BIN_RLOCATION": "$(rlocationpaths {})".format(bin_name),
},
)
py_reconfig_binary(
name = bin_name,
srcs = [py_src],
main = py_src,
tags = ["manual"],
**kwargs
)
def _current_build_settings_impl(ctx):
info = ctx.actions.declare_file(ctx.label.name + ".json")
toolchain = ctx.toolchains[TARGET_TOOLCHAIN_TYPE]
runtime = toolchain.py3_runtime
files = [info]
ctx.actions.write(
output = info,
content = json.encode({
"interpreter": {
"short_path": runtime.interpreter.short_path if runtime.interpreter else None,
},
"interpreter_path": runtime.interpreter_path,
"toolchain_label": str(getattr(toolchain, "toolchain_label", None)),
}),
)
return [DefaultInfo(
files = depset(files),
)]
current_build_settings = rule(
doc = """
Writes information about the current build config to JSON for testing.
This is so tests can verify information about the build config used for them.
""",
implementation = _current_build_settings_impl,
toolchains = [
TARGET_TOOLCHAIN_TYPE,
],
)