Skip to content

Commit 8e7fd8c

Browse files
committed
feat: split download and install steps
1 parent 3ee8115 commit 8e7fd8c

8 files changed

+363
-112
lines changed

python/extensions.bzl

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ def _poetry_impl(module_ctx):
77
poetry_venv(
88
name = attr.name,
99
lock = attr.lock,
10+
platforms = attr.platforms,
1011
)
1112

1213
poetry = module_extension(
@@ -16,6 +17,7 @@ poetry = module_extension(
1617
attrs = {
1718
"name": attr.string(mandatory = True),
1819
"lock": attr.label(mandatory = True),
20+
"platforms": attr.string_dict(),
1921
},
2022
),
2123
},

python/poetry_deps.bzl

+105-39
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,38 @@ load("@bazel_skylib//lib:versions.bzl", "versions")
33
load("//python:markers.bzl", "evaluate", "parse")
44

55
# Environment Markers https://peps.python.org/pep-0508/#environment-markers
6-
_INTERPRETER_MARKERS = {
7-
"aarch64-apple-darwin": """{"platform_system": "Darwin", "platform_tag": ["macosx_11_0_arm64", "macosx_12_0_arm64"], "sys_platform": "darwin", "os_name": "posix"}""",
8-
"aarch64-unknown-linux-gnu": """{"platform_system": "Linux", "platform_tag": "manylinux_2_17_arm64", "sys_platform": "linux", "os_name": "posix"}""",
9-
"x86_64-apple-darwin": """{"platform_system": "Darwin", "platform_tag": "macosx_10_15_x86_64", "sys_platform": "darwin", "os_name": "posix"}""",
10-
"x86_64-pc-windows-msvc": """{"platform_system": "Windows", "platform_tag": "win_amd64", "sys_platform": "win32", "os_name": "nt"}""",
11-
"x86_64-unknown-linux-gnu": """{"platform_system": "Linux", "platform_tag": "manylinux_2_17_x86_64", "sys_platform": "linux", "os_name": "posix"}""",
6+
# Platform tags https://packaging.python.org/en/latest/specifications/platform-compatibility-tags/#platform-tag
7+
_DEFAULT_PLATFORMS = {
8+
"aarch64-apple-darwin": """{"os_name": "posix", "platform_system": "Darwin", "platform_tags": ["macosx_11_0_arm64", "macosx_12_0_arm64"], "sys_platform": "darwin"}""",
9+
"aarch64-unknown-linux-gnu": """{"os_name": "posix", "platform_system": "Linux", "platform_tags": ["manylinux_2_17_arm64"], "sys_platform": "linux"}""",
10+
"x86_64-apple-darwin": """{"os_name": "posix", "platform_system": "Darwin", "platform_tags": ["macosx_10_15_x86_64"], "sys_platform": "darwin"}""",
11+
"x86_64-pc-windows-msvc": """{"os_name": "nt", "platform_system": "Windows", "platform_tags": ["win_amd64"], "sys_platform": "win32"}""",
12+
"x86_64-unknown-linux-gnu": """{"os_name": "posix", "platform_system": "Linux", "platform_tags": ["manylinux_2_12_x86_64", "manylinux_2_17_x86_64"], "sys_platform": "linux"}""",
1213
}
1314

15+
def _get_python_version(interpreter):
16+
parts = interpreter.split("_")
17+
for index in range(len(parts) - 1):
18+
if parts[index].endswith("python3") and parts[index + 1].isdigit():
19+
return "3.{}".format(parts[index + 1])
20+
21+
return "3"
22+
1423
def _derive_environment_markers(interpreter, interpreter_markers):
1524
tags = {
1625
"extra": "*",
1726
"implementation_name": "cpython",
1827
"platform_python_implementation": "CPython",
28+
"python_version": _get_python_version(interpreter),
1929
}
20-
parts = interpreter.split("_")
21-
for index in range(len(parts) - 1):
22-
if parts[index].endswith("python3") and parts[index + 1].isdigit():
23-
tags["python_version"] = "3.{}".format(parts[index + 1])
24-
break
2530

2631
for fr, to in interpreter_markers.items():
2732
if fr in interpreter:
2833
tags.update(**json.decode(to))
2934
return fr, tags
3035

31-
return None, tags
36+
tags["platform_tags"] = []
37+
return "default", tags
3238

3339
def _include_dep(dep, markers, environment):
3440
if not markers:
@@ -40,9 +46,9 @@ def _include_dep(dep, markers, environment):
4046
marker = markers[dep.label.name]
4147
return evaluate(parse(marker, environment))
4248

43-
def _package_impl(ctx):
49+
def _package_wheel_impl(ctx):
4450
"""
45-
Rule to install a Python package.
51+
Rule to download a Python package.
4652
4753
Arguments:
4854
ctx: The rule context.
@@ -53,7 +59,6 @@ def _package_impl(ctx):
5359
deps: label_list The package dependencies list.
5460
files: string_dict The dictionary of resolved file names with corresponding checksum.
5561
markers: string The JSON string with markers accordingly to PEP 508 – Dependency specification for Python Software Packages.
56-
constraints: label_list The list of platform constraints (currently unused).
5762
5863
Private attributes:
5964
_poetry_deps:
@@ -67,14 +72,14 @@ def _package_impl(ctx):
6772

6873
toolchain = ctx.toolchains["@bazel_tools//tools/python:toolchain_type"]
6974
runtime_info = toolchain.py3_runtime
70-
runtime_tag, tags = _derive_environment_markers(runtime_info.interpreter.path, ctx.attr.interpreter_markers)
75+
runtime_tag, tags = _derive_environment_markers(runtime_info.interpreter.path, ctx.attr.platforms)
7176
python_version = tags["python_version"]
72-
platform_tag = tags["platform_tag"]
77+
platform_tags = tags["platform_tags"]
7378

7479
output = ctx.actions.declare_directory("{}/{}/{}".format(python_version, runtime_tag, ctx.label.name))
7580
arguments = [
76-
ctx.attr.name,
77-
ctx.attr.version,
81+
"download",
82+
ctx.attr.constraint,
7883
"--python-version",
7984
python_version,
8085
"--output",
@@ -83,24 +88,87 @@ def _package_impl(ctx):
8388
json.encode(ctx.attr.files),
8489
]
8590

86-
if type(platform_tag) == "string":
87-
arguments += ["--platform", platform_tag]
88-
elif type(platform_tag) == "list":
89-
for platform in tags["platform_tag"]:
90-
arguments += ["--platform", platform]
91-
else:
92-
fail("platform_tag must be either a string o a list of strings")
91+
for platform in platform_tags:
92+
arguments += ["--platform", platform]
93+
94+
ctx.actions.run(
95+
outputs = [output],
96+
mnemonic = "DownloadWheel",
97+
progress_message = "Downloading package {} for Python {} {}".format(ctx.attr.constraint, python_version, runtime_tag),
98+
arguments = arguments,
99+
use_default_shell_env = True,
100+
executable = ctx.executable._poetry_deps,
101+
)
102+
103+
return [
104+
DefaultInfo(files = depset([output])),
105+
]
93106

94-
if ctx.attr.source_url:
95-
arguments += [
96-
"--source-url",
97-
ctx.attr.source_url,
98-
]
107+
package_wheel = rule(
108+
implementation = _package_wheel_impl,
109+
attrs = {
110+
"constraint": attr.string(mandatory = True, doc = "The package version constraint string"),
111+
"description": attr.string(doc = "The package description"),
112+
"files": attr.string_dict(doc = "The package resolved files"),
113+
"platforms": attr.string_dict(
114+
default = _DEFAULT_PLATFORMS,
115+
doc = "The mapping of an interpter substring mapping to environment markers and platform tags as a JSON string. " +
116+
"Default value corresponds to platforms defined at " +
117+
"https://github.com/bazelbuild/rules_python/blob/23cf6b66/python/versions.bzl#L231-L277",
118+
),
119+
"_poetry_deps": attr.label(default = ":poetry_deps", cfg = "exec", executable = True),
120+
},
121+
toolchains = [
122+
"@bazel_tools//tools/python:toolchain_type",
123+
],
124+
)
125+
126+
def _package_impl(ctx):
127+
"""
128+
Rule to install a Python package.
129+
130+
Arguments:
131+
ctx: The rule context.
132+
133+
Attributes:
134+
deps: label_list The package dependencies list.
135+
markers: string The JSON string with markers accordingly to PEP 508 – Dependency specification for Python Software Packages.
136+
137+
Private attributes:
138+
_poetry_deps:
139+
140+
Returns:
141+
The providers list or a tuple with a Poetry package.
142+
143+
Required toolchains:
144+
@bazel_tools//tools/python:toolchain_type
145+
"""
146+
147+
toolchain = ctx.toolchains["@bazel_tools//tools/python:toolchain_type"]
148+
runtime_info = toolchain.py3_runtime
149+
runtime_tag, tags = _derive_environment_markers(runtime_info.interpreter.path, ctx.attr.platforms)
150+
python_version = tags["python_version"]
151+
platform_tags = tags["platform_tags"]
152+
153+
output = ctx.actions.declare_directory("{}/{}/{}".format(python_version, runtime_tag, ctx.label.name))
154+
wheel_file = ctx.attr.wheel.files.to_list().pop()
155+
arguments = [
156+
"install",
157+
"url" if ctx.attr.url else "wheel",
158+
ctx.attr.url if ctx.attr.url else wheel_file.path,
159+
output.path,
160+
"--python-version",
161+
python_version,
162+
]
163+
164+
for platform in platform_tags:
165+
arguments += ["--platform", platform]
99166

100167
ctx.actions.run(
101168
outputs = [output],
169+
inputs = [] if ctx.attr.url else [wheel_file],
102170
mnemonic = "InstallWheel",
103-
progress_message = "Installing Python package {} for Python {} {}".format(ctx.label.name, python_version, runtime_tag),
171+
progress_message = "Installing package {} for Python {} {}".format(ctx.label.name, python_version, runtime_tag),
104172
arguments = arguments,
105173
use_default_shell_env = True,
106174
executable = ctx.executable._poetry_deps,
@@ -120,15 +188,13 @@ package = rule(
120188
implementation = _package_impl,
121189
provides = [PyInfo],
122190
attrs = {
123-
"version": attr.string(mandatory = True, doc = "The package exact version string"),
124-
"description": attr.string(doc = "The package description"),
125191
"deps": attr.label_list(doc = "The package dependencies list"),
126-
"files": attr.string_dict(doc = "The package resolved files"),
192+
"wheel": attr.label(doc = "The package_wheel target"),
193+
"url": attr.string(doc = "The source file URL"),
127194
"markers": attr.string(doc = "The JSON string with a dictionary of dependency markers accordingly to PEP 508"),
128-
"source_url": attr.string(doc = "The source file URL"),
129-
"interpreter_markers": attr.string_dict(
130-
default = _INTERPRETER_MARKERS,
131-
doc = "The mapping of an interpter substring mapping to environment markers as a JSON string. " +
195+
"platforms": attr.string_dict(
196+
default = _DEFAULT_PLATFORMS,
197+
doc = "The mapping of an interpter substring mapping to environment markers and platform tags as a JSON string. " +
132198
"Default value corresponds to platforms defined at " +
133199
"https://github.com/bazelbuild/rules_python/blob/23cf6b66/python/versions.bzl#L231-L277",
134200
),

0 commit comments

Comments
 (0)