blob: 0f1b75a9b0f9e6b2bddc5cbcd05bf6e6872c65aa [file] [log] [blame]
Lorenz Brun4c4a7042025-10-29 15:37:32 +01001load(
2 "@bazel_tools//tools/build_defs/repo:cache.bzl",
3 "CANONICAL_ID_DOC",
4 "DEFAULT_CANONICAL_ID_ENV",
5 "get_default_canonical_id",
6)
7load(
8 "@bazel_tools//tools/build_defs/repo:utils.bzl",
9 "get_auth",
10 "update_attrs",
11 "workspace_and_buildfile",
12)
13
14_http_archive_deb_attrs = {
15 "url": attr.string(doc = "A URL to a deb file. See http_archive for more info."),
16 "urls": attr.string_list(doc = "A list of URLs to a deb file. See http_archive for more info."),
17 "integrity": attr.string(
18 doc = """Expected checksum in Subresource Integrity format of the file downloaded.
19
20This must match the checksum of the file downloaded. _It is a security risk
21to omit the checksum as remote files can change._ At best omitting this
22field will make your build non-hermetic. It is optional to make development
23easier but this attribute should be set before shipping.""",
24 ),
25 "netrc": attr.string(
26 doc = "Location of the .netrc file to use for authentication",
27 ),
28 "auth_patterns": attr.string_dict(
29 doc = "See http_archive",
30 ),
31 "canonical_id": attr.string(
32 doc = CANONICAL_ID_DOC,
33 ),
34 "build_file": attr.label(
35 allow_single_file = True,
36 doc =
37 "The file to use as the BUILD file for this repository." +
38 "This attribute is an absolute label (use '@//' for the main " +
39 "repo). The file does not need to be named BUILD, but can " +
40 "be (something like BUILD.new-repo-name may work well for " +
41 "distinguishing it from the repository's actual BUILD files. " +
42 "Either build_file or build_file_content can be specified, but " +
43 "not both.",
44 ),
45 "build_file_content": attr.string(
46 doc =
47 "The content for the BUILD file for this repository. " +
48 "Either build_file or build_file_content can be specified, but " +
49 "not both.",
50 ),
51 "workspace_file": attr.label(
52 doc = "No-op attribute; do not use.",
53 ),
54 "workspace_file_content": attr.string(
55 doc = "No-op attribute; do not use.",
56 ),
57}
58
59def _get_source_urls(ctx):
60 """Returns source urls provided via the url, urls attributes.
61
62 Also checks that at least one url is provided."""
63 if not ctx.attr.url and not ctx.attr.urls:
64 fail("At least one of url and urls must be provided")
65
66 source_urls = []
67 if ctx.attr.urls:
68 source_urls = ctx.attr.urls
69 if ctx.attr.url:
70 source_urls = [ctx.attr.url] + source_urls
71 return source_urls
72
73def _http_archive_deb_impl(ctx):
74 """Implementation of the http_archive_deb rule."""
75 if ctx.attr.build_file and ctx.attr.build_file_content:
76 fail("Only one of build_file and build_file_content can be provided.")
77
78 source_urls = _get_source_urls(ctx)
79 download_info = ctx.download_and_extract(
80 source_urls,
81 output = "debian-package",
82 type = ".deb",
83 canonical_id = ctx.attr.canonical_id or get_default_canonical_id(ctx, source_urls),
84 auth = get_auth(ctx, source_urls),
85 integrity = ctx.attr.integrity,
86 )
87 files = ctx.path("debian-package").readdir()
88
89 data_archive = None
90 control_archive = None
91 has_marker = False
92 for f in files:
93 if f.basename.startswith("data.tar."):
94 data_archive = f.basename
95 elif f.basename.startswith("control.tar."):
96 control_archive = f.basename
97 elif f.basename == "debian-binary":
98 has_marker = True
99
100 if not has_marker:
101 fail("deb package does not contain a debian-binary marker file, check the file.")
102 if not data_archive:
103 fail("Failed to find data.tar.* archive in .deb contents.")
104 if not control_archive:
105 fail("Failed to find control.tar.* archive in .deb contents.")
106
107 ctx.extract(
108 archive = "debian-package/" + data_archive,
109 )
110 ctx.extract(
111 archive = "debian-package/" + control_archive,
112 output = "debian",
113 )
114 ctx.delete("debian-package")
115 workspace_and_buildfile(ctx)
116
117 if ctx.attr.integrity:
118 return ctx.repo_metadata(reproducible = True)
119
120 return ctx.repo_metadata(attrs_for_reproducibility = update_attrs(ctx.attr, _http_archive_deb_attrs.keys(), {"integrity": download_info.integrity}))
121
122http_archive_deb = repository_rule(
123 implementation = _http_archive_deb_impl,
124 attrs = _http_archive_deb_attrs,
125 environ = [DEFAULT_CANONICAL_ID_ENV],
126 doc = """http_archive for Debian packages. Extracts all contents into a
127 repository, control files are extracted into a `debian` subfolder.""",
128)