blob: bdf8c78147b368a904d3426c620e529ea4e9ebfe [file] [log] [blame]
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
load("@rules_python//python:pip.bzl", "pip_install")
load("@python3//:defs.bzl", "interpreter")
_WHEEL_BUILD_FILE_CONTENTS = """\
package(default_visibility = ["//visibility:public"])
exports_files([
"sanitized_requirements.txt",
])
filegroup(
name = "all_wheels",
srcs = glob(["**/*.whl"])
)
"""
def _pip_wheel_impl(rctx):
# First, check if an existing pre-built Python wheels repo exists, and if
# so, use it instead of building one.
python_wheel_repo_path = rctx.os.environ.get(
"BAZEL_PYTHON_WHEELS_REPO",
None,
)
if python_wheel_repo_path:
rctx.report_progress("Mounting existing Python wheels repo")
rctx.symlink(python_wheel_repo_path, ".")
return
# If a pre-built Python wheels repo does not exist, we need to build it.
rctx.report_progress("No Python wheels repo detected, building it instead")
# First, we install the Python wheel package so we can build other wheels.
args = [
rctx.path(rctx.attr.python_interpreter),
"-m",
"pip",
"install",
"-U",
"--ignore-installed",
"wheel",
]
rctx.report_progress("Installing the Python wheel package")
result = rctx.execute(
args,
timeout = rctx.attr.timeout,
quiet = rctx.attr.quiet,
)
if result.return_code:
fail("pip_wheel failed: {} ({})".format(result.stdout, result.stderr))
# Next, we download/build all the Python wheels for each requirement.
args = [
rctx.path(rctx.attr.python_interpreter),
"-m",
"pip",
"wheel",
"-r",
rctx.path(rctx.attr.requirements),
"-w",
"./",
]
rctx.report_progress("Pre-building Python wheels")
result = rctx.execute(
args,
timeout = rctx.attr.timeout,
quiet = rctx.attr.quiet,
)
if result.return_code:
fail("pip_wheel failed: {} ({})".format(result.stdout, result.stderr))
# Last, we generate a new Python requirements file that does not contain any
# VCS links. We avoid just patching the existing python_requirements.txt
# file, and instead generate a requirements file based on the wheels that
# were built above. This enables us to make changes to the main
# python_requirements.txt file without impacting this step.
args = [rctx.path(rctx.attr._gen_requirements_script)]
rctx.report_progress("Generating sanitzed requirements file")
result = rctx.execute(
args,
timeout = rctx.attr.timeout,
quiet = rctx.attr.quiet,
working_directory = "./",
)
if result.return_code:
fail("pip_wheel failed: {} ({})".format(result.stdout, result.stderr))
# We need a BUILD file to load the downloaded Python packages.
rctx.file(
"BUILD.bazel",
_WHEEL_BUILD_FILE_CONTENTS,
)
pip_wheel = repository_rule(
implementation = _pip_wheel_impl,
attrs = {
"python_interpreter": attr.label(
default = interpreter,
allow_single_file = True,
doc = "Python interpreter to use.",
),
"requirements": attr.label(
default = "//:python-requirements.txt",
allow_single_file = True,
doc = "Python requirements file describing package dependencies.",
),
"quiet": attr.bool(
default = True,
doc = "If True, suppress printing stdout/stderr to the terminal.",
),
"timeout": attr.int(
default = 300,
doc = "Timeout (in seconds) on the rule's execution duration.",
),
"_gen_requirements_script": attr.label(
default = "//third_party/python:gen_requirements.sh",
allow_single_file = True,
doc = "Shell script that generates a requirements file without VCS links.",
executable = True,
cfg = "exec",
),
},
environ = ["BAZEL_PYTHON_WHEELS_REPO"],
)
def pip_deps():
pip_wheel(
name = "ot_python_wheels",
)
pip_install(
name = "ot_python_deps",
python_interpreter_target = interpreter,
requirements = "@ot_python_wheels//:sanitized_requirements.txt",
find_links = "@ot_python_wheels//:all_wheels",
extra_pip_args = ["--no-index"],
)