Skip to content

Commit 1c87068

Browse files
committed
use sha256 for ensuring that pip repo names are valid and dont clash
1 parent 5c80375 commit 1c87068

File tree

6 files changed

+106
-16
lines changed

6 files changed

+106
-16
lines changed

python/private/BUILD.bazel

+9
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,15 @@ bzl_library(
153153
],
154154
)
155155

156+
bzl_library(
157+
name = "pip_repo_name_bzl",
158+
srcs = ["pip_repo_name.bzl"],
159+
deps = [
160+
":normalize_name_bzl",
161+
":parse_whl_name_bzl",
162+
],
163+
)
164+
156165
bzl_library(
157166
name = "pypi_index_bzl",
158167
srcs = ["pypi_index.bzl"],

python/private/bzlmod/BUILD.bazel

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ bzl_library(
3636
"//python/private:normalize_name_bzl",
3737
"//python/private:parse_requirements_bzl",
3838
"//python/private:parse_whl_name_bzl",
39+
"//python/private:pip_repo_name_bzl",
3940
"//python/private:version_label_bzl",
4041
":bazel_features_bzl",
4142
] + [

python/private/bzlmod/pip.bzl

+2-16
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ load("//python/private:auth.bzl", "AUTH_ATTRS")
2626
load("//python/private:normalize_name.bzl", "normalize_name")
2727
load("//python/private:parse_requirements.bzl", "host_platform", "parse_requirements", "select_requirement")
2828
load("//python/private:parse_whl_name.bzl", "parse_whl_name")
29+
load("//python/private:pip_repo_name.bzl", "pip_repo_name")
2930
load("//python/private:pypi_index.bzl", "simpleapi_download")
3031
load("//python/private:render_pkg_aliases.bzl", "whl_alias")
3132
load("//python/private:repo_utils.bzl", "repo_utils")
@@ -260,7 +261,7 @@ def _create_whl_repos(module_ctx, pip_attr, whl_map, whl_overrides, group_map, s
260261
# This is no-op because pip is not used to download the wheel.
261262
whl_library_args.pop("download_only", None)
262263

263-
repo_name = _repo_name(pip_name, distribution.filename)
264+
repo_name = pip_repo_name(pip_name, distribution.filename, distribution.sha256)
264265
whl_library_args["requirement"] = requirement.srcs.requirement
265266
whl_library_args["urls"] = [distribution.url]
266267
whl_library_args["sha256"] = distribution.sha256
@@ -317,21 +318,6 @@ def _create_whl_repos(module_ctx, pip_attr, whl_map, whl_overrides, group_map, s
317318
),
318319
)
319320

320-
def _repo_name(prefix, filename):
321-
if not filename.endswith(".whl"):
322-
# Then the filename is basically foo-3.2.1.<ext>
323-
name = normalize_name(filename)
324-
else:
325-
parsed = parse_whl_name(filename)
326-
name = "{}_{}_{}_{}_{}".format(
327-
parsed.distribution,
328-
parsed.version,
329-
parsed.python_tag,
330-
parsed.abi_tag,
331-
parsed.platform_tag,
332-
)
333-
return "{}__{}".format(prefix, normalize_name(name))
334-
335321
def _pip_impl(module_ctx):
336322
"""Implementation of a class tag that creates the pip hub and corresponding pip spoke whl repositories.
337323

python/private/pip_repo_name.bzl

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright 2024 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
"""A function to convert a dist name to a valid bazel repo name.
16+
"""
17+
18+
load(":normalize_name.bzl", "normalize_name")
19+
load(":parse_whl_name.bzl", "parse_whl_name")
20+
21+
def pip_repo_name(prefix, filename, sha256):
22+
"""Return a valid whl_library repo name given a distribution filename.
23+
24+
Args:
25+
prefix: str, the prefix of the whl_library.
26+
filename: str, the filename of the distribution.
27+
sha256: str, the sha256 of the distribution.
28+
29+
Returns:
30+
a string that can be used in `whl_library`.
31+
"""
32+
if not filename.endswith(".whl"):
33+
# Then the filename is basically foo-3.2.1.<ext>
34+
name = normalize_name(filename.rpartition("-")[0])
35+
else:
36+
parsed = parse_whl_name(filename)
37+
name = normalize_name(parsed.distribution)
38+
39+
return "{}__{}_{}".format(prefix, name, sha256[:8])
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
load(":pip_repo_name_tests.bzl", "pip_repo_name_test_suite")
2+
3+
pip_repo_name_test_suite(name = "pip_repo_name_tests")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Copyright 2023 The Bazel Authors. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
""
16+
17+
load("@rules_testing//lib:test_suite.bzl", "test_suite")
18+
load("//python/private:pip_repo_name.bzl", "pip_repo_name") # buildifier: disable=bzl-visibility
19+
20+
_tests = []
21+
22+
def _test_simple(env):
23+
got = pip_repo_name("prefix", "foo-1.2.3-py3-none-any.whl", "deadbeef")
24+
env.expect.that_str(got).equals("prefix__foo_deadbeef")
25+
26+
_tests.append(_test_simple)
27+
28+
def _test_sdist(env):
29+
got = pip_repo_name("prefix", "foo-1.2.3.tar.gz", "deadbeef000deadbeef")
30+
env.expect.that_str(got).equals("prefix__foo_deadbeef")
31+
32+
_tests.append(_test_sdist)
33+
34+
def _test_platform_whl(env):
35+
got = pip_repo_name(
36+
"prefix",
37+
"foo-1.2.3-cp39.cp310-abi3-manylinux1_x86_64.manylinux_2_17_x86_64.whl",
38+
"deadbeef000deadbeef",
39+
)
40+
41+
# We only need the first segment of each
42+
env.expect.that_str(got).equals("prefix__foo_deadbeef")
43+
44+
_tests.append(_test_platform_whl)
45+
46+
def pip_repo_name_test_suite(name):
47+
"""Create the test suite.
48+
49+
Args:
50+
name: the name of the test suite
51+
"""
52+
test_suite(name = name, basic_tests = _tests)

0 commit comments

Comments
 (0)