@@ -3,32 +3,38 @@ load("@bazel_skylib//lib:versions.bzl", "versions")
3
3
load ("//python:markers.bzl" , "evaluate" , "parse" )
4
4
5
5
# 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"}""" ,
12
13
}
13
14
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
+
14
23
def _derive_environment_markers (interpreter , interpreter_markers ):
15
24
tags = {
16
25
"extra" : "*" ,
17
26
"implementation_name" : "cpython" ,
18
27
"platform_python_implementation" : "CPython" ,
28
+ "python_version" : _get_python_version (interpreter ),
19
29
}
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
25
30
26
31
for fr , to in interpreter_markers .items ():
27
32
if fr in interpreter :
28
33
tags .update (** json .decode (to ))
29
34
return fr , tags
30
35
31
- return None , tags
36
+ tags ["platform_tags" ] = []
37
+ return "default" , tags
32
38
33
39
def _include_dep (dep , markers , environment ):
34
40
if not markers :
@@ -40,9 +46,9 @@ def _include_dep(dep, markers, environment):
40
46
marker = markers [dep .label .name ]
41
47
return evaluate (parse (marker , environment ))
42
48
43
- def _package_impl (ctx ):
49
+ def _package_wheel_impl (ctx ):
44
50
"""
45
- Rule to install a Python package.
51
+ Rule to download a Python package.
46
52
47
53
Arguments:
48
54
ctx: The rule context.
@@ -53,7 +59,6 @@ def _package_impl(ctx):
53
59
deps: label_list The package dependencies list.
54
60
files: string_dict The dictionary of resolved file names with corresponding checksum.
55
61
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).
57
62
58
63
Private attributes:
59
64
_poetry_deps:
@@ -67,14 +72,14 @@ def _package_impl(ctx):
67
72
68
73
toolchain = ctx .toolchains ["@bazel_tools//tools/python:toolchain_type" ]
69
74
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 )
71
76
python_version = tags ["python_version" ]
72
- platform_tag = tags ["platform_tag " ]
77
+ platform_tags = tags ["platform_tags " ]
73
78
74
79
output = ctx .actions .declare_directory ("{}/{}/{}" .format (python_version , runtime_tag , ctx .label .name ))
75
80
arguments = [
76
- ctx . attr . name ,
77
- ctx .attr .version ,
81
+ "download" ,
82
+ ctx .attr .constraint ,
78
83
"--python-version" ,
79
84
python_version ,
80
85
"--output" ,
@@ -83,24 +88,87 @@ def _package_impl(ctx):
83
88
json .encode (ctx .attr .files ),
84
89
]
85
90
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
+ ]
93
106
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 ]
99
166
100
167
ctx .actions .run (
101
168
outputs = [output ],
169
+ inputs = [] if ctx .attr .url else [wheel_file ],
102
170
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 ),
104
172
arguments = arguments ,
105
173
use_default_shell_env = True ,
106
174
executable = ctx .executable ._poetry_deps ,
@@ -120,15 +188,13 @@ package = rule(
120
188
implementation = _package_impl ,
121
189
provides = [PyInfo ],
122
190
attrs = {
123
- "version" : attr .string (mandatory = True , doc = "The package exact version string" ),
124
- "description" : attr .string (doc = "The package description" ),
125
191
"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" ),
127
194
"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. " +
132
198
"Default value corresponds to platforms defined at " +
133
199
"https://github.com/bazelbuild/rules_python/blob/23cf6b66/python/versions.bzl#L231-L277" ,
134
200
),
0 commit comments