@@ -20,9 +20,17 @@ load("@bazel_features//:features.bzl", "bazel_features")
20
20
load ("//python/private:auth.bzl" , "get_auth" )
21
21
load ("//python/private:envsubst.bzl" , "envsubst" )
22
22
load ("//python/private:normalize_name.bzl" , "normalize_name" )
23
+ load ("//python/private:text_util.bzl" , "render" )
23
24
load (":parse_simpleapi_html.bzl" , "parse_simpleapi_html" )
24
25
25
- def simpleapi_download (ctx , * , attr , cache , parallel_download = True ):
26
+ def simpleapi_download (
27
+ ctx ,
28
+ * ,
29
+ attr ,
30
+ cache ,
31
+ parallel_download = True ,
32
+ read_simpleapi = None ,
33
+ _fail = fail ):
26
34
"""Download Simple API HTML.
27
35
28
36
Args:
@@ -49,6 +57,9 @@ def simpleapi_download(ctx, *, attr, cache, parallel_download = True):
49
57
reflected when re-evaluating the extension unless we do
50
58
`bazel clean --expunge`.
51
59
parallel_download: A boolean to enable usage of bazel 7.1 non-blocking downloads.
60
+ read_simpleapi: a function for reading and parsing of the SimpleAPI contents.
61
+ Used in tests.
62
+ _fail: a function to print a failure. Used in tests.
52
63
53
64
Returns:
54
65
dict of pkg name to the parsed HTML contents - a list of structs.
@@ -64,15 +75,22 @@ def simpleapi_download(ctx, *, attr, cache, parallel_download = True):
64
75
65
76
# NOTE @aignas 2024-03-31: we are not merging results from multiple indexes
66
77
# to replicate how `pip` would handle this case.
67
- async_downloads = {}
68
78
contents = {}
69
79
index_urls = [attr .index_url ] + attr .extra_index_urls
70
- for pkg in attr .sources :
71
- pkg_normalized = normalize_name (pkg )
72
-
73
- success = False
74
- for index_url in index_urls :
75
- result = _read_simpleapi (
80
+ read_simpleapi = read_simpleapi or _read_simpleapi
81
+
82
+ found_on_index = {}
83
+ warn_overrides = False
84
+ for i , index_url in enumerate (index_urls ):
85
+ if i != 0 :
86
+ # Warn the user about a potential fix for the overrides
87
+ warn_overrides = True
88
+
89
+ async_downloads = {}
90
+ sources = [pkg for pkg in attr .sources if pkg not in found_on_index ]
91
+ for pkg in sources :
92
+ pkg_normalized = normalize_name (pkg )
93
+ result = read_simpleapi (
76
94
ctx = ctx ,
77
95
url = "{}/{}/" .format (
78
96
index_url_overrides .get (pkg_normalized , index_url ).rstrip ("/" ),
@@ -84,42 +102,45 @@ def simpleapi_download(ctx, *, attr, cache, parallel_download = True):
84
102
)
85
103
if hasattr (result , "wait" ):
86
104
# We will process it in a separate loop:
87
- async_downloads .setdefault (pkg_normalized , []).append (
88
- struct (
89
- pkg_normalized = pkg_normalized ,
90
- wait = result .wait ,
91
- ),
105
+ async_downloads [pkg ] = struct (
106
+ pkg_normalized = pkg_normalized ,
107
+ wait = result .wait ,
92
108
)
93
- continue
94
-
95
- if result .success :
109
+ elif result .success :
96
110
contents [pkg_normalized ] = result .output
97
- success = True
98
- break
99
-
100
- if not async_downloads and not success :
101
- fail ("Failed to download metadata from urls: {}" .format (
102
- ", " .join (index_urls ),
103
- ))
104
-
105
- if not async_downloads :
106
- return contents
107
-
108
- # If we use `block` == False, then we need to have a second loop that is
109
- # collecting all of the results as they were being downloaded in parallel.
110
- for pkg , downloads in async_downloads .items ():
111
- success = False
112
- for download in downloads :
111
+ found_on_index [pkg ] = index_url
112
+
113
+ if not async_downloads :
114
+ continue
115
+
116
+ # If we use `block` == False, then we need to have a second loop that is
117
+ # collecting all of the results as they were being downloaded in parallel.
118
+ for pkg , download in async_downloads .items ():
113
119
result = download .wait ()
114
120
115
- if result .success and download . pkg_normalized not in contents :
121
+ if result .success :
116
122
contents [download .pkg_normalized ] = result .output
117
- success = True
118
-
119
- if not success :
120
- fail ("Failed to download metadata from urls: {}" .format (
121
- ", " .join (index_urls ),
122
- ))
123
+ found_on_index [pkg ] = index_url
124
+
125
+ failed_sources = [pkg for pkg in attr .sources if pkg not in found_on_index ]
126
+ if failed_sources :
127
+ _fail ("Failed to download metadata for {} for from urls: {}" .format (
128
+ failed_sources ,
129
+ index_urls ,
130
+ ))
131
+ return None
132
+
133
+ if warn_overrides :
134
+ index_url_overrides = {
135
+ pkg : found_on_index [pkg ]
136
+ for pkg in attr .sources
137
+ if found_on_index [pkg ] != attr .index_url
138
+ }
139
+
140
+ # buildifier: disable=print
141
+ print ("You can use the following `index_url_overrides` to avoid the 404 warnings:\n {}" .format (
142
+ render .dict (index_url_overrides ),
143
+ ))
123
144
124
145
return contents
125
146
0 commit comments