@@ -34,7 +34,7 @@ helm_import = rule(
3434 allow_single_file = [".tgz" ],
3535 ),
3636 "version" : attr .string (
37- doc = "The version fo the helm chart" ,
37+ doc = "The version of the helm chart" ,
3838 ),
3939 },
4040)
@@ -60,14 +60,6 @@ def _find_chart_url(repository_ctx, repo_file, chart_name, chart_version):
6060 return url
6161 fail ("cannot find {} (version {}) in {}" .format (chart_name , chart_version , repository_ctx .attr .repository ))
6262
63- def _get_chart_file_name (chart_url ):
64- if chart_url .startswith ("http" ) and chart_url .endswith (".tgz" ):
65- return chart_url .split ("/" )[- 1 ]
66- if chart_url .startswith ("oci" ):
67- chart_name , chart_version = chart_url .split ("/" )[- 1 ].split (":" )
68- return "{}-{}.tgz" .format (chart_name , chart_version )
69- fail ("cannot determine chart file name from {}" .format (chart_url ))
70-
7163def _find_chart_digest (manifest ):
7264 for layer in manifest ["layers" ]:
7365 # https://helm.sh/docs/topics/registries/#helm-chart-manifest
@@ -83,141 +75,203 @@ helm_import(
8375 chart = "{chart_file}",
8476 visibility = ["//visibility:public"],
8577)
78+ """
8679
87- alias(
88- name = "{repository_name}",
89- actual = ":{chart_name}",
90- visibility = ["//visibility:public"],
80+ def _helm_import_url_impl (repository_ctx ):
81+ chart_name = repository_ctx .attr .chart_name
82+ chart_url = repository_ctx .attr .url
83+
84+ chart_file = "{}.tgz" .format (chart_name )
85+
86+ repository_ctx .file ("BUILD.bazel" , content = _HELM_DEP_BUILD_FILE .format (
87+ chart_name = chart_name ,
88+ chart_file = chart_file ,
89+ ))
90+
91+ chart_package = repository_ctx .download (
92+ output = repository_ctx .path (chart_file ),
93+ url = chart_url ,
94+ sha256 = repository_ctx .attr .sha256 ,
95+ )
96+
97+ return {
98+ "chart_name" : chart_name ,
99+ "name" : repository_ctx .name ,
100+ "sha256" : chart_package .sha256 ,
101+ "url" : chart_url ,
102+ }
103+
104+ helm_import_url = repository_rule (
105+ implementation = _helm_import_url_impl ,
106+ attrs = {
107+ "chart_name" : attr .string (
108+ doc = "Chart name to import." ,
109+ mandatory = True ,
110+ ),
111+ "sha256" : attr .string (
112+ doc = "The expected SHA-256 hash of the chart imported." ,
113+ ),
114+ "url" : attr .string (
115+ doc = "The URL where the chart can be directly downloaded." ,
116+ mandatory = True ,
117+ ),
118+ },
91119)
92- """
93120
94- def _helm_import_repository_impl (repository_ctx ):
95- if repository_ctx .attr .url and repository_ctx .attr .repository :
96- fail ("`url` and `repository` are exclusive arguments." )
97-
98- if repository_ctx .attr .url :
99- chart_url = repository_ctx .attr .url
100- if repository_ctx .attr .chart_name :
101- fail ("`url` provided, do not set `chart_name`" )
102- if repository_ctx .attr .version :
103- fail ("`url` provided, do not set `version`" )
104- else :
105- if not repository_ctx .attr .chart_name :
106- fail ("`chart_name` is required to locate chart" )
107- if not repository_ctx .attr .version :
108- fail ("`version` is required to locate chart" )
109-
110- repo_yaml = "index.yaml"
111- repository_ctx .download (
112- output = repo_yaml ,
113- url = "{}/{}" .format (
114- repository_ctx .attr .repository ,
115- repo_yaml ,
116- ),
117- )
121+ def _oci_url_download (repository_ctx , url , chart_file ):
122+ url , _ , chart_version = url .rpartition (":" )
123+ hostname , _ , chart_path = url .removeprefix ("oci://" ).partition ("/" )
124+
125+ au = authn .new (repository_ctx )
126+ token = au .get_token (hostname , chart_path )
127+
128+ manifest_json = "manifest.json"
129+ manifest_url = "https://{}/v2/{}/manifests/{}" .format (
130+ hostname ,
131+ chart_path ,
132+ chart_version ,
133+ )
134+ repository_ctx .download (
135+ output = manifest_json ,
136+ url = manifest_url ,
137+ auth = {
138+ manifest_url : token ,
139+ },
140+ # Copied from `helm pull --debug`
141+ headers = {
142+ "Accept" : [
143+ "application/vnd.docker.distribution.manifest.v2+json" ,
144+ "application/vnd.docker.distribution.manifest.list.v2+json" ,
145+ "application/vnd.oci.image.manifest.v1+json" ,
146+ "application/vnd.oci.image.index.v1+json" ,
147+ "*/*" ,
148+ ],
149+ },
150+ )
151+ manifest = json .decode (repository_ctx .read (manifest_json ))
118152
119- chart_url = _find_chart_url (repository_ctx , repo_yaml , repository_ctx .attr .chart_name , repository_ctx .attr .version )
153+ # https://helm.sh/docs/topics/registries/#helm-chart-manifest
154+ if manifest ["config" ]["mediaType" ] != "application/vnd.cncf.helm.config.v1+json" :
155+ fail ("oci://{}/{} is not a Helm chart package" .format (hostname , chart_path ))
120156
121- chart_file = _get_chart_file_name (chart_url )
157+ chart_digest = _find_chart_digest (manifest )
158+ chart_blob_url = "https://{}/v2/{}/blobs/{}" .format (
159+ hostname ,
160+ chart_path ,
161+ chart_digest ,
162+ )
163+
164+ # Download the chart package:
165+ return repository_ctx .download (
166+ output = repository_ctx .path (chart_file ),
167+ url = chart_blob_url ,
168+ sha256 = repository_ctx .attr .sha256 ,
169+ auth = {
170+ chart_blob_url : token ,
171+ },
172+ )
173+
174+ def _helm_import_repository_impl (repository_ctx ):
175+ chart_name = repository_ctx .attr .chart_name
176+ chart_version = repository_ctx .attr .version
177+
178+ repo_yaml = "index.yaml"
179+ repository_ctx .download (
180+ output = repo_yaml ,
181+ url = "{}/{}" .format (
182+ repository_ctx .attr .repository ,
183+ repo_yaml ,
184+ ),
185+ )
186+ chart_url = _find_chart_url (repository_ctx , repo_yaml , chart_name , chart_version )
187+ chart_file = "{}.tgz" .format (chart_name )
122188
123189 if chart_url .startswith ("http" ):
124- result = repository_ctx .download (
190+ chart_package = repository_ctx .download (
125191 output = repository_ctx .path (chart_file ),
126192 url = chart_url ,
127193 sha256 = repository_ctx .attr .sha256 ,
128194 )
129195 elif chart_url .startswith ("oci" ):
130- url , _ , chart_version = chart_url .rpartition (":" )
131- hostname , _ , chart_path = url .removeprefix ("oci://" ).partition ("/" )
132-
133- au = authn .new (repository_ctx )
134- token = au .get_token (hostname , chart_path )
135-
136- # Find the digest for the layer with the chart package in the image manifest:
137- manifest_json = "manifest.json"
138- manifest_url = "https://{}/v2/{}/manifests/{}" .format (
139- hostname ,
140- chart_path ,
141- chart_version ,
142- )
143- repository_ctx .download (
144- output = manifest_json ,
145- url = manifest_url ,
146- auth = {
147- manifest_url : token ,
148- },
149- # Copied from `helm pull --debug`
150- headers = {
151- "Accept" : [
152- "application/vnd.docker.distribution.manifest.v2+json" ,
153- "application/vnd.docker.distribution.manifest.list.v2+json" ,
154- "application/vnd.oci.image.manifest.v1+json" ,
155- "application/vnd.oci.image.index.v1+json" ,
156- "*/*" ,
157- ],
158- },
159- )
160- manifest = json .decode (repository_ctx .read (manifest_json ))
161-
162- # https://helm.sh/docs/topics/registries/#helm-chart-manifest
163- if manifest ["config" ]["mediaType" ] != "application/vnd.cncf.helm.config.v1+json" :
164- fail ("{} is not a Helm chart package" .format (chart_url ))
165-
166- chart_digest = _find_chart_digest (manifest )
167- chart_blob_url = "https://{}/v2/{}/blobs/{}" .format (
168- hostname ,
169- chart_path ,
170- chart_digest ,
171- )
172-
173- # Download the chart package:
174- result = repository_ctx .download (
175- output = repository_ctx .path (chart_file ),
176- url = chart_blob_url ,
177- sha256 = repository_ctx .attr .sha256 ,
178- auth = {
179- chart_blob_url : token ,
180- },
181- )
182-
196+ chart_package = _oci_url_download (repository_ctx , chart_url , chart_file )
183197 else :
184- fail ("cannot download {} from {}, unsupported scheme" .format (repository_ctx .attr .chart_name , chart_url ))
185-
186- chart_name , _ , chart_version = chart_file .removesuffix (".tgz" ).rpartition ("-" )
198+ fail ("cannot download {} from {}, unsupported scheme" .format (chart_name , chart_url ))
187199
188200 repository_ctx .file ("BUILD.bazel" , content = _HELM_DEP_BUILD_FILE .format (
189201 chart_name = chart_name ,
190202 chart_file = chart_file ,
191- repository_name = repository_ctx .name ,
192203 ))
193204
194205 return {
195206 "chart_name" : chart_name ,
196207 "name" : repository_ctx .name ,
197208 "repository" : repository_ctx .attr .repository ,
198- "sha256" : result .sha256 ,
199- "url" : chart_url ,
209+ "sha256" : chart_package .sha256 ,
200210 "version" : chart_version ,
201211 }
202212
203213helm_import_repository = repository_rule (
204214 implementation = _helm_import_repository_impl ,
205- doc = "A rule for fetching external Helm charts from an arbitrary URL or repository." ,
215+ doc = "A rule for fetching external Helm chart from a HTTP repository." ,
206216 attrs = {
207217 "chart_name" : attr .string (
208- doc = "Chart name to import. Must be set if `repository` is specified" ,
218+ doc = "Chart name to import." ,
219+ mandatory = True ,
209220 ),
210221 "repository" : attr .string (
211- doc = "Chart repository url where to locate the requested chart. Mutually exclusive with `url`." ,
222+ doc = "Repository URL where to locate the specified chart." ,
223+ mandatory = True ,
212224 ),
213225 "sha256" : attr .string (
214226 doc = "The expected SHA-256 hash of the chart imported." ,
215227 ),
216- "url" : attr .string (
217- doc = "The url where a chart can be directly downloaded. Mutually exclusive with `chart_name`, `repository`, and `version`" ,
228+ "version" : attr .string (
229+ doc = "Chart version to import." ,
230+ mandatory = True ,
231+ ),
232+ },
233+ )
234+
235+ def _helm_import_registry_impl (repository_ctx ):
236+ registry = repository_ctx .attr .registry
237+ chart_name = repository_ctx .attr .chart_name
238+ version = repository_ctx .attr .version
239+
240+ chart_url = "{}/{}:{}" .format (registry , chart_name , version )
241+ chart_file = "{}.tgz" .format (chart_name )
242+ chart_package = _oci_url_download (repository_ctx , chart_url , chart_file )
243+
244+ repository_ctx .file ("BUILD.bazel" , content = _HELM_DEP_BUILD_FILE .format (
245+ chart_name = chart_name ,
246+ chart_file = chart_file ,
247+ ))
248+
249+ return {
250+ "chart_name" : chart_name ,
251+ "name" : repository_ctx .name ,
252+ "registry" : repository_ctx .attr .registry ,
253+ "sha256" : chart_package .sha256 ,
254+ "version" : repository_ctx .attr .version ,
255+ }
256+
257+ helm_import_registry = repository_rule (
258+ implementation = _helm_import_registry_impl ,
259+ doc = "A rule for fetching an external Helm chart from a OCI registry." ,
260+ attrs = {
261+ "chart_name" : attr .string (
262+ doc = "Chart name to import." ,
263+ mandatory = True ,
264+ ),
265+ "registry" : attr .string (
266+ doc = "OCI registry URL where to locate the specified chart." ,
267+ mandatory = True ,
268+ ),
269+ "sha256" : attr .string (
270+ doc = "The expected SHA-256 hash of the chart imported." ,
218271 ),
219272 "version" : attr .string (
220- doc = "Specify a version constraint for the chart version to use. Must be set if `repository` is specified." ,
273+ doc = "Chart version to import." ,
274+ mandatory = True ,
221275 ),
222276 },
223277)
0 commit comments