Skip to content

Commit 6461a69

Browse files
authored
fix(whl_library): avoid unnecessary repository rule restarts (bazel-contrib#1400)
Put the `PYTHONPATH` entries used in wheel building as a default value to a private attribute of the `whl_library` repository rule and use resolved path of the interpreter target in creating execution environment to avoid repository rule restarts when fetching external dependencies. The extra private attribute on the `whl_library` removes all but one restart and the extra refactor removes the last restart observed when running, which also reduces the total execution time from around 50s to 43s on my machine: ```console $ cd examples/bzlmod $ bazel clean --expunge --async && bazel build //entry_points:yamllint ``` Fixes bazel-contrib#1399
1 parent 9818a60 commit 6461a69

File tree

3 files changed

+37
-34
lines changed

3 files changed

+37
-34
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ A brief description of the categories of changes:
3131
* (bzlmod) The `entry_point` macro is no longer supported and has been removed
3232
in favour of the `py_console_script_binary` macro for `bzlmod` users.
3333

34+
### Fixed
35+
36+
* (whl_library) No longer restarts repository rule when fetching external
37+
dependencies improving initial build times involving external dependency
38+
fetching.
39+
3440
## [0.25.0] - 2023-08-22
3541

3642
### Changed

python/pip_install/pip_repository.bzl

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
""
1616

17-
load("//python:repositories.bzl", "get_interpreter_dirname", "is_standalone_interpreter")
17+
load("//python:repositories.bzl", "is_standalone_interpreter")
1818
load("//python:versions.bzl", "WINDOWS_NAME")
1919
load("//python/pip_install:repositories.bzl", "all_requirements")
2020
load("//python/pip_install:requirements_parser.bzl", parse_requirements = "parse")
@@ -43,15 +43,11 @@ def _construct_pypath(rctx):
4343
Returns: String of the PYTHONPATH.
4444
"""
4545

46-
# Get the root directory of these rules
47-
rules_root = rctx.path(Label("//:BUILD.bazel")).dirname
48-
thirdparty_roots = [
49-
# Includes all the external dependencies from repositories.bzl
50-
rctx.path(Label("@" + repo + "//:BUILD.bazel")).dirname
51-
for repo in all_requirements
52-
]
5346
separator = ":" if not "windows" in rctx.os.name.lower() else ";"
54-
pypath = separator.join([str(p) for p in [rules_root] + thirdparty_roots])
47+
pypath = separator.join([
48+
str(rctx.path(entry).dirname)
49+
for entry in rctx.attr._python_path_entries
50+
])
5551
return pypath
5652

5753
def _get_python_interpreter_attr(rctx):
@@ -123,7 +119,7 @@ def _get_xcode_location_cflags(rctx):
123119
"-isysroot {}/SDKs/MacOSX.sdk".format(xcode_root),
124120
]
125121

126-
def _get_toolchain_unix_cflags(rctx):
122+
def _get_toolchain_unix_cflags(rctx, python_interpreter):
127123
"""Gather cflags from a standalone toolchain for unix systems.
128124
129125
Pip won't be able to compile c extensions from sdists with the pre built python distributions from indygreg
@@ -135,19 +131,19 @@ def _get_toolchain_unix_cflags(rctx):
135131
return []
136132

137133
# Only update the location when using a standalone toolchain.
138-
if not is_standalone_interpreter(rctx, rctx.attr.python_interpreter_target):
134+
if not is_standalone_interpreter(rctx, python_interpreter):
139135
return []
140136

141137
er = rctx.execute([
142-
rctx.path(rctx.attr.python_interpreter_target).realpath,
138+
python_interpreter,
143139
"-c",
144140
"import sys; print(f'{sys.version_info[0]}.{sys.version_info[1]}', end='')",
145141
])
146142
if er.return_code != 0:
147143
fail("could not get python version from interpreter (status {}): {}".format(er.return_code, er.stderr))
148144
_python_version = er.stdout
149145
include_path = "{}/include/python{}".format(
150-
get_interpreter_dirname(rctx, rctx.attr.python_interpreter_target),
146+
python_interpreter.dirname,
151147
_python_version,
152148
)
153149

@@ -218,19 +214,20 @@ def _parse_optional_attrs(rctx, args):
218214

219215
return args
220216

221-
def _create_repository_execution_environment(rctx):
217+
def _create_repository_execution_environment(rctx, python_interpreter):
222218
"""Create a environment dictionary for processes we spawn with rctx.execute.
223219
224220
Args:
225-
rctx: The repository context.
221+
rctx (repository_ctx): The repository context.
222+
python_interpreter (path): The resolved python interpreter.
226223
Returns:
227224
Dictionary of environment variable suitable to pass to rctx.execute.
228225
"""
229226

230227
# Gather any available CPPFLAGS values
231228
cppflags = []
232229
cppflags.extend(_get_xcode_location_cflags(rctx))
233-
cppflags.extend(_get_toolchain_unix_cflags(rctx))
230+
cppflags.extend(_get_toolchain_unix_cflags(rctx, python_interpreter))
234231

235232
env = {
236233
"PYTHONPATH": _construct_pypath(rctx),
@@ -630,7 +627,7 @@ def _whl_library_impl(rctx):
630627
result = rctx.execute(
631628
args,
632629
# Manually construct the PYTHONPATH since we cannot use the toolchain here
633-
environment = _create_repository_execution_environment(rctx),
630+
environment = _create_repository_execution_environment(rctx, python_interpreter),
634631
quiet = rctx.attr.quiet,
635632
timeout = rctx.attr.timeout,
636633
)
@@ -720,6 +717,19 @@ whl_library_attrs = {
720717
mandatory = True,
721718
doc = "Python requirement string describing the package to make available",
722719
),
720+
"_python_path_entries": attr.label_list(
721+
# Get the root directory of these rules and keep them as a default attribute
722+
# in order to avoid unnecessary repository fetching restarts.
723+
#
724+
# This is very similar to what was done in https://github.com/bazelbuild/rules_go/pull/3478
725+
default = [
726+
Label("//:BUILD.bazel"),
727+
] + [
728+
# Includes all the external dependencies from repositories.bzl
729+
Label("@" + repo + "//:BUILD.bazel")
730+
for repo in all_requirements
731+
],
732+
),
723733
}
724734

725735
whl_library_attrs.update(**common_attrs)

python/repositories.bzl

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -61,39 +61,26 @@ def py_repositories():
6161

6262
STANDALONE_INTERPRETER_FILENAME = "STANDALONE_INTERPRETER"
6363

64-
def get_interpreter_dirname(rctx, python_interpreter_target):
65-
"""Get a python interpreter target dirname.
66-
67-
Args:
68-
rctx (repository_ctx): The repository rule's context object.
69-
python_interpreter_target (Target): A target representing a python interpreter.
70-
71-
Returns:
72-
str: The Python interpreter directory.
73-
"""
74-
75-
return rctx.path(Label("{}//:WORKSPACE".format(str(python_interpreter_target).split("//")[0]))).dirname
76-
77-
def is_standalone_interpreter(rctx, python_interpreter_target):
64+
def is_standalone_interpreter(rctx, python_interpreter_path):
7865
"""Query a python interpreter target for whether or not it's a rules_rust provided toolchain
7966
8067
Args:
8168
rctx (repository_ctx): The repository rule's context object.
82-
python_interpreter_target (Target): A target representing a python interpreter.
69+
python_interpreter_path (path): A path representing the interpreter.
8370
8471
Returns:
8572
bool: Whether or not the target is from a rules_python generated toolchain.
8673
"""
8774

8875
# Only update the location when using a hermetic toolchain.
89-
if not python_interpreter_target:
76+
if not python_interpreter_path:
9077
return False
9178

9279
# This is a rules_python provided toolchain.
9380
return rctx.execute([
9481
"ls",
9582
"{}/{}".format(
96-
get_interpreter_dirname(rctx, python_interpreter_target),
83+
python_interpreter_path.dirname,
9784
STANDALONE_INTERPRETER_FILENAME,
9885
),
9986
]).return_code == 0

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy