blob: 73752f70cd95d39652241580228524c41298abbd [file] [log] [blame]
Tim Windelschmidt156248b2025-01-10 00:27:45 +01001def _build_pure_transition_impl(settings, _attr):
Serge Bazanskic3ae7582020-06-08 17:15:26 +02002 """
3 Transition that enables pure, static build of Go binaries.
4 """
Tim Windelschmidt3a171d12024-12-09 23:51:23 +01005 race = settings["@io_bazel_rules_go//go/config:race"]
Serge Bazanski30021af2023-06-20 13:30:11 +02006 pure = not race
7
Serge Bazanskic3ae7582020-06-08 17:15:26 +02008 return {
Serge Bazanski30021af2023-06-20 13:30:11 +02009 "@io_bazel_rules_go//go/config:pure": pure,
Serge Bazanskic3ae7582020-06-08 17:15:26 +020010 "@io_bazel_rules_go//go/config:static": True,
Tim Windelschmidt3a171d12024-12-09 23:51:23 +010011 "//command_line_option:platforms": "//build/platforms:linux_amd64_static",
Serge Bazanskic3ae7582020-06-08 17:15:26 +020012 }
13
14build_pure_transition = transition(
15 implementation = _build_pure_transition_impl,
Serge Bazanski30021af2023-06-20 13:30:11 +020016 inputs = [
17 "@io_bazel_rules_go//go/config:race",
18 ],
Serge Bazanskic3ae7582020-06-08 17:15:26 +020019 outputs = [
20 "@io_bazel_rules_go//go/config:pure",
21 "@io_bazel_rules_go//go/config:static",
Tim Windelschmidt3a171d12024-12-09 23:51:23 +010022 "//command_line_option:platforms",
Serge Bazanskic3ae7582020-06-08 17:15:26 +020023 ],
24)
25
Tim Windelschmidt156248b2025-01-10 00:27:45 +010026def _build_static_transition_impl(_settings, _attr):
Lorenz Brun5e4fc2d2020-09-22 18:35:15 +020027 """
28 Transition that enables static builds with CGo and musl for Go binaries.
29 """
30 return {
31 "@io_bazel_rules_go//go/config:static": True,
Leopoldbc93c2b2023-01-14 13:12:23 +010032 "//command_line_option:platforms": "//build/platforms:linux_amd64_static",
Lorenz Brun5e4fc2d2020-09-22 18:35:15 +020033 }
34
35build_static_transition = transition(
36 implementation = _build_static_transition_impl,
37 inputs = [],
38 outputs = [
39 "@io_bazel_rules_go//go/config:static",
Leopoldbc93c2b2023-01-14 13:12:23 +010040 "//command_line_option:platforms",
Lorenz Brun5e4fc2d2020-09-22 18:35:15 +020041 ],
42)
43
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +010044FSSpecInfo = provider(
45 "Provides parts of an FSSpec used to assemble filesystem images",
46 fields = {
47 "spec": "File containing the partial FSSpec as prototext",
48 "referenced": "Files (potentially) referenced by the spec",
Serge Bazanski140bddc2020-06-05 21:01:19 +020049 },
50)
Lorenz Brun6b13bf12021-01-26 19:54:24 +010051
Lorenz Brunb69a71c2024-12-23 14:12:46 +010052def fsspec_core_impl(ctx, tool, output_file, extra_files = [], extra_fsspecs = []):
Lorenz Brun6b13bf12021-01-26 19:54:24 +010053 """
Lorenz Brunb69a71c2024-12-23 14:12:46 +010054 fsspec_core_impl implements the core of an fsspec-based rule. It takes
Serge Bazanskia3938142022-04-04 17:04:47 +020055 input from the `files`,`files_cc`, `symlinks` and `fsspecs` attributes
56 and calls `tool` with the `-out` parameter pointing to `output_file`
57 and paths to all fsspecs as positional arguments.
Lorenz Brun6b13bf12021-01-26 19:54:24 +010058 """
Lorenz Brun6b13bf12021-01-26 19:54:24 +010059 fs_spec_name = ctx.label.name + ".prototxt"
60 fs_spec = ctx.actions.declare_file(fs_spec_name)
61
62 fs_files = []
63 inputs = []
Lorenz Brunb69a71c2024-12-23 14:12:46 +010064 for label, p in ctx.attr.files.items() + ctx.attr.files_cc.items() + extra_files:
Lorenz Brun6b13bf12021-01-26 19:54:24 +010065 if not p.startswith("/"):
66 fail("file {} invalid: must begin with /".format(p))
67
68 # Figure out if this is an executable.
69 is_executable = True
70
71 di = label[DefaultInfo]
72 if di.files_to_run.executable == None:
73 # Generated non-executable files will have DefaultInfo.files_to_run.executable == None
74 is_executable = False
75 elif di.files_to_run.executable.is_source:
76 # Source files will have executable.is_source == True
77 is_executable = False
78
79 # Ensure only single output is declared.
80 # If you hit this error, figure out a better logic to find what file you need, maybe looking at providers other
81 # than DefaultInfo.
82 files = di.files.to_list()
83 if len(files) > 1:
84 fail("file {} has more than one output: {}", p, files)
85 src = files[0]
86 inputs.append(src)
87
88 mode = 0o555 if is_executable else 0o444
89 fs_files.append(struct(path = p, source_path = src.path, mode = mode, uid = 0, gid = 0))
90
Lorenz Brun6b13bf12021-01-26 19:54:24 +010091 fs_symlinks = []
92 for target, p in ctx.attr.symlinks.items():
93 fs_symlinks.append(struct(path = p, target_path = target))
94
Serge Bazanskia3938142022-04-04 17:04:47 +020095 fs_spec_content = struct(file = fs_files, directory = [], symbolic_link = fs_symlinks)
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +010096 ctx.actions.write(fs_spec, proto.encode_text(fs_spec_content))
Lorenz Brun6b13bf12021-01-26 19:54:24 +010097
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +010098 extra_specs = []
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +010099
Lorenz Brunb69a71c2024-12-23 14:12:46 +0100100 for fsspec in ctx.attr.fsspecs + extra_fsspecs:
Lorenz Brund1bc4a62022-09-12 16:45:18 +0000101 if FSSpecInfo in fsspec:
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100102 fsspec_info = fsspec[FSSpecInfo]
103 extra_specs.append(fsspec_info.spec)
104 for f in fsspec_info.referenced:
Lorenz Brund1bc4a62022-09-12 16:45:18 +0000105 inputs.append(f)
106 else:
107 # Raw .fsspec prototext. No referenced data allowed.
108 di = fsspec[DefaultInfo]
109 extra_specs += di.files.to_list()
Serge Bazanskia3938142022-04-04 17:04:47 +0200110
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100111 ctx.actions.run(
112 outputs = [output_file],
113 inputs = [fs_spec] + inputs + extra_specs,
114 tools = [tool],
115 executable = tool,
116 arguments = ["-out", output_file.path, fs_spec.path] + [s.path for s in extra_specs],
117 )
118 return
119
120def _node_initramfs_impl(ctx):
Lorenz Brun62f1d362023-11-14 16:18:24 +0100121 initramfs_name = ctx.label.name + ".cpio.zst"
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100122 initramfs = ctx.actions.declare_file(initramfs_name)
123
Lorenz Brunb69a71c2024-12-23 14:12:46 +0100124 fsspec_core_impl(ctx, ctx.executable._mkcpio, initramfs)
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100125
126 # TODO(q3k): Document why this is needed
127 return [DefaultInfo(runfiles = ctx.runfiles(files = [initramfs]), files = depset([initramfs]))]
128
129node_initramfs = rule(
130 implementation = _node_initramfs_impl,
131 doc = """
132 Build a node initramfs. The initramfs will contain a basic /dev directory and all the files specified by the
133 `files` attribute. Executable files will have their permissions set to 0755, non-executable files will have
134 their permissions set to 0444. All parent directories will be created with 0755 permissions.
135 """,
136 attrs = {
137 "files": attr.label_keyed_string_dict(
138 mandatory = True,
139 allow_files = True,
140 doc = """
141 Dictionary of Labels to String, placing a given Label's output file in the initramfs at the location
142 specified by the String value. The specified labels must only have a single output.
143 """,
144 # Attach pure transition to ensure all binaries added to the initramfs are pure/static binaries.
145 cfg = build_pure_transition,
146 ),
147 "files_cc": attr.label_keyed_string_dict(
148 allow_files = True,
149 doc = """
150 Special case of 'files' for compilation targets that need to be built with the musl toolchain like
151 go_binary targets which need cgo or cc_binary targets.
152 """,
153 # Attach static transition to all files_cc inputs to ensure they are built with musl and static.
154 cfg = build_static_transition,
155 ),
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100156 "symlinks": attr.string_dict(
157 default = {},
158 doc = """
159 Symbolic links to create. Similar format as in files and files_cc, so the target of the symlink is the
160 key and the value of it is the location of the symlink itself. Only raw strings are allowed as targets,
161 labels are not permitted. Include the file using files or files_cc, then symlink to its location.
162 """,
163 ),
164 "fsspecs": attr.label_list(
165 default = [],
166 doc = """
Tim Windelschmidtc2290c22024-08-15 19:56:00 +0200167 List of file system specs (osbase.build.fsspec.FSSpec) to also include in the resulting image.
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100168 These will be merged with all other given attributes.
169 """,
170 providers = [FSSpecInfo],
Serge Bazanskia3938142022-04-04 17:04:47 +0200171 allow_files = True,
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100172 ),
173
174 # Tool
175 "_mkcpio": attr.label(
Tim Windelschmidtc2290c22024-08-15 19:56:00 +0200176 default = Label("//osbase/build/mkcpio"),
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100177 executable = True,
178 cfg = "exec",
179 ),
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100180 },
181)
182
183def _erofs_image_impl(ctx):
Lorenz Brun6b13bf12021-01-26 19:54:24 +0100184 fs_name = ctx.label.name + ".img"
185 fs_out = ctx.actions.declare_file(fs_name)
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100186
Lorenz Brunb69a71c2024-12-23 14:12:46 +0100187 fsspec_core_impl(ctx, ctx.executable._mkerofs, fs_out)
Lorenz Brun6b13bf12021-01-26 19:54:24 +0100188
189 return [DefaultInfo(files = depset([fs_out]))]
190
191erofs_image = rule(
192 implementation = _erofs_image_impl,
193 doc = """
194 Build an EROFS. All files specified in files, files_cc and all specified symlinks will be contained.
195 Executable files will have their permissions set to 0555, non-executable files will have
196 their permissions set to 0444. All parent directories will be created with 0555 permissions.
197 """,
198 attrs = {
199 "files": attr.label_keyed_string_dict(
200 mandatory = True,
201 allow_files = True,
202 doc = """
203 Dictionary of Labels to String, placing a given Label's output file in the EROFS at the location
204 specified by the String value. The specified labels must only have a single output.
205 """,
206 # Attach pure transition to ensure all binaries added to the initramfs are pure/static binaries.
207 cfg = build_pure_transition,
208 ),
209 "files_cc": attr.label_keyed_string_dict(
210 allow_files = True,
211 doc = """
212 Special case of 'files' for compilation targets that need to be built with the musl toolchain like
213 go_binary targets which need cgo or cc_binary targets.
214 """,
215 # Attach static transition to all files_cc inputs to ensure they are built with musl and static.
216 cfg = build_static_transition,
217 ),
Lorenz Brun6b13bf12021-01-26 19:54:24 +0100218 "symlinks": attr.string_dict(
219 default = {},
220 doc = """
221 Symbolic links to create. Similar format as in files and files_cc, so the target of the symlink is the
222 key and the value of it is the location of the symlink itself. Only raw strings are allowed as targets,
223 labels are not permitted. Include the file using files or files_cc, then symlink to its location.
224 """,
225 ),
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100226 "fsspecs": attr.label_list(
227 default = [],
228 doc = """
Tim Windelschmidtc2290c22024-08-15 19:56:00 +0200229 List of file system specs (osbase.build.fsspec.FSSpec) to also include in the resulting image.
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100230 These will be merged with all other given attributes.
231 """,
232 providers = [FSSpecInfo],
Serge Bazanskia3938142022-04-04 17:04:47 +0200233 allow_files = True,
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100234 ),
Lorenz Brun6b13bf12021-01-26 19:54:24 +0100235
236 # Tools, implicit dependencies.
237 "_mkerofs": attr.label(
Tim Windelschmidtc2290c22024-08-15 19:56:00 +0200238 default = Label("//osbase/build/mkerofs"),
Lorenz Brun6b13bf12021-01-26 19:54:24 +0100239 executable = True,
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100240 cfg = "exec",
Lorenz Brun6b13bf12021-01-26 19:54:24 +0100241 ),
Lorenz Brun6b13bf12021-01-26 19:54:24 +0100242 },
243)
Mateusz Zalegae2bf5742022-01-25 19:36:08 +0100244
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100245# VerityInfo is emitted by verity_image, and contains a file enclosing a
Mateusz Zalegae2bf5742022-01-25 19:36:08 +0100246# singular dm-verity target table.
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100247VerityInfo = provider(
248 "Information necessary to mount a single dm-verity target.",
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100249 fields = {
250 "table": "A file containing the dm-verity target table. See: https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html",
251 },
Mateusz Zalegae2bf5742022-01-25 19:36:08 +0100252)
253
254def _verity_image_impl(ctx):
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100255 """
256 Create a new file containing the source image data together with the Verity
257 metadata appended to it, and provide an associated DeviceMapper Verity target
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100258 table in a separate file, through VerityInfo provider.
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100259 """
Mateusz Zalegae2bf5742022-01-25 19:36:08 +0100260
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100261 # Run mkverity.
262 image = ctx.actions.declare_file(ctx.attr.name + ".img")
263 table = ctx.actions.declare_file(ctx.attr.name + ".dmt")
264 ctx.actions.run(
265 mnemonic = "GenVerityImage",
Tim Windelschmidt83f0aa42024-12-09 20:34:33 +0100266 progress_message = "Generating a dm-verity image: {}".format(image.short_path),
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100267 inputs = [ctx.file.source],
268 outputs = [
269 image,
270 table,
271 ],
272 executable = ctx.file._mkverity,
273 arguments = [
274 "-input=" + ctx.file.source.path,
275 "-output=" + image.path,
276 "-table=" + table.path,
277 "-data_alias=" + ctx.attr.rootfs_partlabel,
278 "-hash_alias=" + ctx.attr.rootfs_partlabel,
279 ],
Mateusz Zalegae2bf5742022-01-25 19:36:08 +0100280 )
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100281
282 return [
283 DefaultInfo(
284 files = depset([image]),
285 runfiles = ctx.runfiles(files = [image]),
286 ),
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100287 VerityInfo(
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100288 table = table,
289 ),
290 ]
Mateusz Zalegae2bf5742022-01-25 19:36:08 +0100291
292verity_image = rule(
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100293 implementation = _verity_image_impl,
294 doc = """
Mateusz Zalegae2bf5742022-01-25 19:36:08 +0100295 Build a dm-verity target image by appending Verity metadata to the source
296 image. A corresponding dm-verity target table will be made available
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100297 through VerityInfo provider.
Mateusz Zalegae2bf5742022-01-25 19:36:08 +0100298 """,
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100299 attrs = {
300 "source": attr.label(
301 doc = "A source image.",
302 allow_single_file = True,
303 ),
304 "rootfs_partlabel": attr.string(
305 doc = "GPT partition label of the rootfs to be used with dm-mod.create.",
Lorenz Brun35fcf032023-06-29 04:15:58 +0200306 default = "PARTLABEL=METROPOLIS-SYSTEM-X",
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100307 ),
308 "_mkverity": attr.label(
309 doc = "The mkverity executable needed to generate the image.",
Tim Windelschmidtc2290c22024-08-15 19:56:00 +0200310 default = "//osbase/build/mkverity",
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100311 allow_single_file = True,
312 executable = True,
Tim Windelschmidt156248b2025-01-10 00:27:45 +0100313 cfg = "exec",
Lorenz Brunb6a9d3c2022-01-27 18:56:20 +0100314 ),
315 },
Mateusz Zalegae2bf5742022-01-25 19:36:08 +0100316)