_mock_pip = """
def _pip_install_impl(repository_ctx):
repository_ctx.file("BUILD.bazel", '''
py_library(
name = "noop",
visibility = ["//visibility:public"],
)
''')
repository_ctx.file("requirements.bzl", '''
def install_deps(*args, **kwargs):
print("WARNING: could not install pip dependencies")
def requirement(*args, **kwargs):
return "@{}//:noop"
'''.format(repository_ctx.attr.name))
pip_install = repository_rule(
implementation = _pip_install_impl,
attrs = {
"requirements": attr.string(),
"requirements_overrides": attr.string_dict(),
"python_interpreter_target": attr.string(),
},
)
pip_parse = pip_install
"""
_alias_pip = """
load("@rules_python//python:pip.bzl", _pip_install = "pip_install", _pip_parse = "pip_parse")
def _get_requirements(requirements, requirements_overrides):
for version, override in requirements_overrides.items():
if version in "{python_version}":
requirements = override
break
return requirements
def pip_install(requirements, requirements_overrides={{}}, **kwargs):
_pip_install(
python_interpreter_target = "@{repo}//:interpreter",
requirements = _get_requirements(requirements, requirements_overrides),
**kwargs,
)
def pip_parse(requirements, requirements_overrides={{}}, **kwargs):
_pip_parse(
python_interpreter_target = "@{repo}//:interpreter",
requirements = _get_requirements(requirements, requirements_overrides),
**kwargs,
)
"""
_mock_fuzzing_py = """
def fuzzing_py_install_deps():
print("WARNING: could not install fuzzing_py dependencies")
"""
_alias_fuzzing_py = """
load("@fuzzing_py_deps//:requirements.bzl", _fuzzing_py_install_deps = "install_deps")
def fuzzing_py_install_deps():
_fuzzing_py_install_deps()
"""
_build_file = """
load("@bazel_skylib//lib:selects.bzl", "selects")
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
load("@bazel_tools//tools/python:toolchain.bzl", "py_runtime_pair")
cc_library(
name = "python_headers",
hdrs = glob(["python/**/*.h"], allow_empty = True),
includes = ["python"],
visibility = ["//visibility:public"],
)
string_flag(
name = "internal_python_support",
build_setting_default = "{support}",
values = [
"None",
"Supported",
"Unsupported",
]
)
config_setting(
name = "none",
flag_values = {{
":internal_python_support": "None",
}},
visibility = ["//visibility:public"],
)
config_setting(
name = "supported",
flag_values = {{
":internal_python_support": "Supported",
}},
visibility = ["//visibility:public"],
)
config_setting(
name = "unsupported",
flag_values = {{
":internal_python_support": "Unsupported",
}},
visibility = ["//visibility:public"],
)
selects.config_setting_group(
name = "exists",
match_any = [":supported", ":unsupported"],
visibility = ["//visibility:public"],
)
sh_binary(
name = "interpreter",
srcs = ["interpreter"],
visibility = ["//visibility:public"],
)
py_runtime(
name = "py3_runtime",
interpreter_path = "{interpreter}",
python_version = "PY3",
)
py_runtime_pair(
name = "runtime_pair",
py3_runtime = ":py3_runtime",
)
toolchain(
name = "python_toolchain",
toolchain = ":runtime_pair",
toolchain_type = "@rules_python//python:toolchain_type",
)
"""
_register = """
def register_system_python():
native.register_toolchains("@{}//:python_toolchain")
"""
_mock_register = """
def register_system_python():
pass
"""
def _get_python_version(repository_ctx):
py_program = "import sys; print(str(sys.version_info.major) + '.' + str(sys.version_info.minor) + '.' + str(sys.version_info.micro))"
result = repository_ctx.execute(["python3", "-c", py_program])
return (result.stdout).strip().split(".")
def _get_python_path(repository_ctx):
py_program = "import sysconfig; print(sysconfig.get_config_var('%s'), end='')"
result = repository_ctx.execute(["python3", "-c", py_program % ("INCLUDEPY")])
if result.return_code != 0:
return None
return result.stdout
def _populate_package(ctx, path, python3, python_version):
ctx.symlink(path, "python")
supported = True
for idx, v in enumerate(ctx.attr.minimum_python_version.split(".")):
if int(python_version[idx]) < int(v):
supported = False
break
if "win" in ctx.os.name:
print("WARNING: python is not supported on Windows")
supported = False
build_file = _build_file.format(
interpreter = python3,
support = "Supported" if supported else "Unsupported",
)
ctx.file("interpreter", "#!/bin/sh\nexec {} \"$@\"".format(python3))
ctx.file("BUILD.bazel", build_file)
ctx.file("version.bzl", "SYSTEM_PYTHON_VERSION = '{}{}'".format(python_version[0], python_version[1]))
ctx.file("register.bzl", _register.format(ctx.attr.name))
if supported:
ctx.file("pip.bzl", _alias_pip.format(
python_version = ".".join(python_version),
repo = ctx.attr.name,
))
ctx.file("fuzzing_py.bzl", _alias_fuzzing_py)
else:
ctx.file("pip.bzl", _mock_pip)
ctx.file("fuzzing_py.bzl", _mock_fuzzing_py)
def _populate_empty_package(ctx):
ctx.file(
"BUILD.bazel",
_build_file.format(
interpreter = "",
support = "None",
),
)
ctx.file("version.bzl", "SYSTEM_PYTHON_VERSION = 'None'")
ctx.file("register.bzl", _mock_register)
ctx.file("pip.bzl", _mock_pip)
ctx.file("fuzzing_py.bzl", _mock_fuzzing_py)
def _system_python_impl(repository_ctx):
path = _get_python_path(repository_ctx)
python3 = repository_ctx.which("python3")
python_version = _get_python_version(repository_ctx)
if path and python_version[0] == "3":
_populate_package(repository_ctx, path, python3, python_version)
else:
print("WARNING: no system python available, builds against system python will fail")
_populate_empty_package(repository_ctx)
system_python = repository_rule(
implementation = _system_python_impl,
local = True,
attrs = {
"minimum_python_version": attr.string(default = "3.7"),
},
)