-
-
Notifications
You must be signed in to change notification settings - Fork 638
feat(bzlmod): support bazel downloader when downloading wheels #1827
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
6720945
927310c
677ed2d
fa1569e
8eb2ee5
11f94c7
3efd55c
186a2c9
506d838
956213a
cdf0510
6651bc9
7d7abd1
fec7abb
ec8dbc4
6f7a42c
7addb40
0313f75
307819e
652d75c
6ca8a4b
d21a29e
affbb32
2da0b29
5ba7881
bb30b41
26c678c
186af97
88ce003
41b23af
fcf2700
b6740f5
3c905ae
459b1ba
095222e
134a8fc
a7b92f5
27307f0
8fe82ba
1d7a063
0a6b850
f0eff9c
097009a
ff3983a
37c3ede
09c724d
1331193
02f7e89
b05094b
881211a
8fc212c
b76bd05
9acf7d3
01eccf5
e80d37c
28d40e3
bdfef56
0b1de6e
9b0be62
8dc3bdc
5b6a444
f438e6e
038e45e
04953d4
02ccc55
b4a9aa8
d620037
f30a5df
aefd8e2
ed4e8ab
5643866
eb67002
d984559
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,7 +4,7 @@ module( | |
| compatibility_level = 1, | ||
| ) | ||
|
|
||
| bazel_dep(name = "bazel_features", version = "1.1.1") | ||
| bazel_dep(name = "bazel_features", version = "1.9.1") | ||
| bazel_dep(name = "bazel_skylib", version = "1.3.0") | ||
| bazel_dep(name = "platforms", version = "0.0.4") | ||
|
|
||
|
|
@@ -58,6 +58,7 @@ register_toolchains("@pythons_hub//:all") | |
|
|
||
| pip = use_extension("//python/extensions:pip.bzl", "pip") | ||
| pip.parse( | ||
| experimental_index_url = "https://pypi.org/simple", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is it intentional not to use PIP_INDEX_URL env here, and why?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If you want to override this value you can use bazel downloader config. In the general sense it is not a given that people will have their Hence to avoid unintended breakage, this is hardcoded. |
||
| hub_name = "rules_python_publish_deps", | ||
| python_version = "3.11", | ||
| requirements_darwin = "//tools/publish:requirements_darwin.txt", | ||
|
|
@@ -69,7 +70,7 @@ use_repo(pip, "rules_python_publish_deps") | |
| # ===== DEV ONLY DEPS AND SETUP BELOW HERE ===== | ||
| bazel_dep(name = "stardoc", version = "0.6.2", dev_dependency = True, repo_name = "io_bazel_stardoc") | ||
| bazel_dep(name = "rules_bazel_integration_test", version = "0.20.0", dev_dependency = True) | ||
| bazel_dep(name = "rules_testing", version = "0.5.0", dev_dependency = True) | ||
| bazel_dep(name = "rules_testing", version = "0.6.0", dev_dependency = True) | ||
| bazel_dep(name = "rules_cc", version = "0.0.9", dev_dependency = True) | ||
|
|
||
| # Extra gazelle plugin deps so that WORKSPACE.bzlmod can continue including it for e2e tests. | ||
|
|
@@ -83,6 +84,8 @@ dev_pip = use_extension( | |
| dev_dependency = True, | ||
| ) | ||
| dev_pip.parse( | ||
| envsubst = ["PIP_INDEX_URL"], | ||
| experimental_index_url = "${PIP_INDEX_URL:-https://pypi.org/simple}", | ||
| experimental_requirement_cycles = { | ||
| "sphinx": [ | ||
| "sphinx", | ||
|
|
@@ -98,6 +101,8 @@ dev_pip.parse( | |
| requirements_lock = "//docs/sphinx:requirements.txt", | ||
| ) | ||
| dev_pip.parse( | ||
| envsubst = ["PIP_INDEX_URL"], | ||
| experimental_index_url = "${PIP_INDEX_URL:-https://pypi.org/simple}", | ||
| hub_name = "pypiserver", | ||
| python_version = "3.11", | ||
| requirements_lock = "//examples/wheel:requirements_server.txt", | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -22,6 +22,7 @@ load("//python/pip_install:requirements_parser.bzl", parse_requirements = "parse | |||||
| load("//python/pip_install/private:generate_group_library_build_bazel.bzl", "generate_group_library_build_bazel") | ||||||
| load("//python/pip_install/private:generate_whl_library_build_bazel.bzl", "generate_whl_library_build_bazel") | ||||||
| load("//python/pip_install/private:srcs.bzl", "PIP_INSTALL_PY_SRCS") | ||||||
| load("//python/private:auth.bzl", "AUTH_ATTRS", "get_auth") | ||||||
| load("//python/private:envsubst.bzl", "envsubst") | ||||||
| load("//python/private:normalize_name.bzl", "normalize_name") | ||||||
| load("//python/private:parse_whl_name.bzl", "parse_whl_name") | ||||||
|
|
@@ -187,7 +188,7 @@ def use_isolated(ctx, attr): | |||||
|
|
||||||
| return use_isolated | ||||||
|
|
||||||
| def _parse_optional_attrs(rctx, args): | ||||||
| def _parse_optional_attrs(rctx, args, extra_pip_args = None): | ||||||
| """Helper function to parse common attributes of pip_repository and whl_library repository rules. | ||||||
|
|
||||||
| This function also serializes the structured arguments as JSON | ||||||
|
|
@@ -196,6 +197,7 @@ def _parse_optional_attrs(rctx, args): | |||||
| Args: | ||||||
| rctx: Handle to the rule repository context. | ||||||
| args: A list of parsed args for the rule. | ||||||
| extra_pip_args: The pip args to pass. | ||||||
| Returns: Augmented args list. | ||||||
| """ | ||||||
|
|
||||||
|
|
@@ -212,7 +214,7 @@ def _parse_optional_attrs(rctx, args): | |||||
|
|
||||||
| # Check for None so we use empty default types from our attrs. | ||||||
| # Some args want to be list, and some want to be dict. | ||||||
| if rctx.attr.extra_pip_args != None: | ||||||
| if extra_pip_args != None: | ||||||
| args += [ | ||||||
| "--extra_pip_args", | ||||||
| json.encode(struct(arg = [ | ||||||
|
|
@@ -759,24 +761,64 @@ def _whl_library_impl(rctx): | |||||
| "--requirement", | ||||||
| rctx.attr.requirement, | ||||||
| ] | ||||||
|
|
||||||
| args = _parse_optional_attrs(rctx, args) | ||||||
| extra_pip_args = [] | ||||||
| extra_pip_args.extend(rctx.attr.extra_pip_args) | ||||||
|
|
||||||
| # Manually construct the PYTHONPATH since we cannot use the toolchain here | ||||||
| environment = _create_repository_execution_environment(rctx, python_interpreter) | ||||||
|
|
||||||
| repo_utils.execute_checked( | ||||||
| rctx, | ||||||
| op = "whl_library.ResolveRequirement({}, {})".format(rctx.attr.name, rctx.attr.requirement), | ||||||
| arguments = args, | ||||||
| environment = environment, | ||||||
| quiet = rctx.attr.quiet, | ||||||
| timeout = rctx.attr.timeout, | ||||||
| ) | ||||||
| whl_path = None | ||||||
| if rctx.attr.whl_file: | ||||||
| whl_path = rctx.path(rctx.attr.whl_file) | ||||||
|
|
||||||
| # Simulate the behaviour where the whl is present in the current directory. | ||||||
| rctx.symlink(whl_path, whl_path.basename) | ||||||
| whl_path = rctx.path(whl_path.basename) | ||||||
| elif rctx.attr.urls: | ||||||
| filename = rctx.attr.filename | ||||||
| urls = rctx.attr.urls | ||||||
| if not filename: | ||||||
| _, _, filename = urls[0].rpartition("/") | ||||||
|
|
||||||
| if not (filename.endswith(".whl") or filename.endswith("tar.gz") or filename.endswith(".zip")): | ||||||
| if rctx.attr.filename: | ||||||
| msg = "got '{}'".format(filename) | ||||||
| else: | ||||||
| msg = "detected '{}' from url:\n{}".format(filename, urls[0]) | ||||||
| fail("Only '.whl', '.tar.gz' or '.zip' files are supported, {}".format(msg)) | ||||||
|
|
||||||
| result = rctx.download( | ||||||
| url = urls, | ||||||
| output = filename, | ||||||
| sha256 = rctx.attr.sha256, | ||||||
| auth = get_auth(rctx, urls), | ||||||
| ) | ||||||
|
|
||||||
| if not result.success: | ||||||
| fail("could not download the '{}' from {}:\n{}".format(filename, urls, result)) | ||||||
|
|
||||||
| if filename.endswith(".whl"): | ||||||
| whl_path = rctx.path(rctx.attr.filename) | ||||||
| else: | ||||||
| # It is an sdist and we need to tell PyPI to use a file in this directory | ||||||
| # and not use any indexes. | ||||||
| extra_pip_args.extend(["--no-index", "--find-links", "."]) | ||||||
|
|
||||||
| args = _parse_optional_attrs(rctx, args, extra_pip_args) | ||||||
|
|
||||||
| whl_path = rctx.path(json.decode(rctx.read("whl_file.json"))["whl_file"]) | ||||||
| if not rctx.delete("whl_file.json"): | ||||||
| fail("failed to delete the whl_file.json file") | ||||||
| if not whl_path: | ||||||
| repo_utils.execute_checked( | ||||||
| rctx, | ||||||
| op = "whl_library.ResolveRequirement({}, {})".format(rctx.attr.name, rctx.attr.requirement), | ||||||
| arguments = args, | ||||||
| environment = environment, | ||||||
| quiet = rctx.attr.quiet, | ||||||
| timeout = rctx.attr.timeout, | ||||||
| ) | ||||||
|
|
||||||
| whl_path = rctx.path(json.decode(rctx.read("whl_file.json"))["whl_file"]) | ||||||
| if not rctx.delete("whl_file.json"): | ||||||
| fail("failed to delete the whl_file.json file") | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
|
||||||
| if rctx.attr.whl_patches: | ||||||
| patches = {} | ||||||
|
|
@@ -890,14 +932,18 @@ if __name__ == "__main__": | |||||
| ) | ||||||
| return contents | ||||||
|
|
||||||
| whl_library_attrs = { | ||||||
| # NOTE @aignas 2024-03-21: The usage of dict({}, **common) ensures that all args to `dict` are unique | ||||||
| whl_library_attrs = dict({ | ||||||
rickeylev marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| "annotation": attr.label( | ||||||
| doc = ( | ||||||
| "Optional json encoded file containing annotation to apply to the extracted wheel. " + | ||||||
| "See `package_annotation`" | ||||||
| ), | ||||||
| allow_files = True, | ||||||
| ), | ||||||
| "filename": attr.string( | ||||||
| doc = "Download the whl file to this filename. Only used when the `urls` is passed. If not specified, will be auto-detected from the `urls`.", | ||||||
| ), | ||||||
| "group_deps": attr.string_list( | ||||||
| doc = "List of dependencies to skip in order to break the cycles within a dependency group.", | ||||||
| default = [], | ||||||
|
|
@@ -911,7 +957,18 @@ whl_library_attrs = { | |||||
| ), | ||||||
| "requirement": attr.string( | ||||||
| mandatory = True, | ||||||
| doc = "Python requirement string describing the package to make available", | ||||||
| doc = "Python requirement string describing the package to make available, if 'urls' or 'whl_file' is given, then this only needs to include foo[any_extras] as a bare minimum.", | ||||||
| ), | ||||||
| "sha256": attr.string( | ||||||
| doc = "The sha256 of the downloaded whl. Only used when the `urls` is passed.", | ||||||
| ), | ||||||
| "urls": attr.string_list( | ||||||
| doc = """\ | ||||||
| The list of urls of the whl to be downloaded using bazel downloader. Using this | ||||||
| attr makes `extra_pip_args` and `download_only` ignored.""", | ||||||
| ), | ||||||
| "whl_file": attr.label( | ||||||
| doc = "The whl file that should be used instead of downloading or building the whl.", | ||||||
| ), | ||||||
| "whl_patches": attr.label_keyed_string_dict( | ||||||
| doc = """a label-keyed-string dict that has | ||||||
|
|
@@ -933,9 +990,8 @@ whl_library_attrs = { | |||||
| for repo in all_requirements | ||||||
| ], | ||||||
| ), | ||||||
| } | ||||||
|
|
||||||
| whl_library_attrs.update(**common_attrs) | ||||||
| }, **common_attrs) | ||||||
| whl_library_attrs.update(AUTH_ATTRS) | ||||||
|
|
||||||
| whl_library = repository_rule( | ||||||
| attrs = whl_library_attrs, | ||||||
|
|
||||||
Uh oh!
There was an error while loading. Please reload this page.