Skip to content

Commit e331afe

Browse files
authored
fix: Handle relative paths properly in _absolute_url (#2153)
This updates the simpleapi parser to handle indexes where wheel and sdist may be an index_url relative path. It also organises the conditionals with fewer negations so they're easier to read Fixes: #2150
1 parent b99bb61 commit e331afe

File tree

4 files changed

+61
-11
lines changed

4 files changed

+61
-11
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ A brief description of the categories of changes:
4040
* (gazelle): Fix incorrect use of `t.Fatal`/`t.Fatalf` in tests.
4141
* (toolchain) Omit third-party python packages from coverage reports from
4242
stage2 bootstrap template.
43+
* (bzlmod) Properly handle relative path URLs in parse_simpleapi_html.bzl
4344

4445
### Added
4546
* Nothing yet

Diff for: examples/bzlmod/MODULE.bazel.lock

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: python/private/pypi/parse_simpleapi_html.bzl

+24-9
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def parse_simpleapi_html(*, url, content):
7878
url = _absolute_url(url, dist_url),
7979
sha256 = sha256,
8080
metadata_sha256 = metadata_sha256,
81-
metadata_url = _absolute_url(url, metadata_url),
81+
metadata_url = _absolute_url(url, metadata_url) if metadata_url else "",
8282
yanked = yanked,
8383
)
8484
else:
@@ -109,18 +109,33 @@ def _get_root_directory(url):
109109

110110
return "{}://{}".format(scheme, host)
111111

112+
def _is_downloadable(url):
113+
"""Checks if the URL would be accepted by the Bazel downloader.
114+
115+
This is based on Bazel's HttpUtils::isUrlSupportedByDownloader
116+
"""
117+
return url.startswith("http://") or url.startswith("https://") or url.startswith("file://")
118+
112119
def _absolute_url(index_url, candidate):
120+
if candidate == "":
121+
return candidate
122+
123+
if _is_downloadable(candidate):
124+
return candidate
125+
113126
if candidate.startswith("/"):
114-
# absolute url
127+
# absolute path
115128
root_directory = _get_root_directory(index_url)
116129
return "{}{}".format(root_directory, candidate)
117130

118-
if not candidate.startswith(".."):
119-
return candidate
131+
if candidate.startswith(".."):
132+
# relative path with up references
133+
candidate_parts = candidate.split("..")
134+
last = candidate_parts[-1]
135+
for _ in range(len(candidate_parts) - 1):
136+
index_url, _, _ = index_url.rstrip("/").rpartition("/")
120137

121-
candidate_parts = candidate.split("..")
122-
last = candidate_parts[-1]
123-
for _ in range(len(candidate_parts) - 1):
124-
index_url, _, _ = index_url.rstrip("/").rpartition("/")
138+
return "{}/{}".format(index_url, last.strip("/"))
125139

126-
return "{}/{}".format(index_url, last.strip("/"))
140+
# relative path without up-references
141+
return "{}/{}".format(index_url, candidate)

Diff for: tests/pypi/parse_simpleapi_html/parse_simpleapi_html_tests.bzl

+34
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,40 @@ def _test_whls(env):
255255
yanked = False,
256256
),
257257
),
258+
(
259+
struct(
260+
attrs = [
261+
'href="1.0.0/mypy_extensions-1.0.0-py3-none-any.whl#sha256=deadbeef"',
262+
],
263+
filename = "mypy_extensions-1.0.0-py3-none-any.whl",
264+
url = "https://example.org/simple/mypy_extensions",
265+
),
266+
struct(
267+
filename = "mypy_extensions-1.0.0-py3-none-any.whl",
268+
metadata_sha256 = "",
269+
metadata_url = "",
270+
sha256 = "deadbeef",
271+
url = "https://example.org/simple/mypy_extensions/1.0.0/mypy_extensions-1.0.0-py3-none-any.whl",
272+
yanked = False,
273+
),
274+
),
275+
(
276+
struct(
277+
attrs = [
278+
'href="unknown://example.com/mypy_extensions-1.0.0-py3-none-any.whl#sha256=deadbeef"',
279+
],
280+
filename = "mypy_extensions-1.0.0-py3-none-any.whl",
281+
url = "https://example.org/simple/mypy_extensions",
282+
),
283+
struct(
284+
filename = "mypy_extensions-1.0.0-py3-none-any.whl",
285+
metadata_sha256 = "",
286+
metadata_url = "",
287+
sha256 = "deadbeef",
288+
url = "https://example.org/simple/mypy_extensions/unknown://example.com/mypy_extensions-1.0.0-py3-none-any.whl",
289+
yanked = False,
290+
),
291+
),
258292
]
259293

260294
for (input, want) in tests:

0 commit comments

Comments
 (0)