From c4c45271a47e50027ece5f7b0704c450669e13f8 Mon Sep 17 00:00:00 2001 From: Dan Fuhry Date: Mon, 19 Oct 2026 17:10:11 -0400 Subject: [PATCH] [bazel] add sqfs_package rule --- bazel/sqfs.bzl | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 bazel/sqfs.bzl diff --git a/bazel/sqfs.bzl b/bazel/sqfs.bzl new file mode 100644 index 0000000..2c7fead --- /dev/null +++ b/bazel/sqfs.bzl @@ -0,0 +1,95 @@ +load("@bazel_skylib//lib:paths.bzl", "paths") + +def _sqfs_package_impl(ctx): + """Implementation rule for sqfs_package.""" + output = ctx.actions.declare_file(ctx.label.name) + + # Build pseudo-file specifications for mksquashfs -p entries. + # Each binary becomes bin/ inside the squashfs image. + # Symlinks are resolved to their targets so mksquashfs can read them. + pseudo_files = [ + "bin d 0755 0 0", + ] + all_files = depset() + for binary in ctx.attr.binaries: + file_list = binary.files.to_list() + file = file_list[0] + all_files = depset(transitive = [all_files, binary.files]) + basename = paths.basename(file.path) + if basename.endswith(".symlink"): + # Resolve the symlink target; use absolute path so it works + # inside mksquashfs's chroot. + pseudo_files.append( + "bin/{} f 0755 0 0 cat $(readlink -f \"{}\")".format( + basename, + file.path, + ), + ) + else: + pseudo_files.append( + "bin/{} f 0755 0 0 cat {}".format( + basename, + file.path, + ), + ) + + ctx.actions.run_shell( + outputs = [output], + inputs = all_files, + tools = depset([ctx.executable.mksquashfs]), + command = """ + export SOURCE_DATE_EPOCH=665374440; \ + mkdir /tmp/emptydir.$$$$; \ + exec {mksquashfs} /tmp/emptydir.$$$$ $@ \ + -force-uid 0 -force-gid 0 -root-uid 0 -root-gid 0 \ + -comp zstd -exit-on-error -no-recovery \ + -p "{pseudo}" + """.format( + mksquashfs = ctx.executable.mksquashfs.path, + pseudo = '" -p "'.join(pseudo_files), + ), + arguments = [output.path], + ) + + return [ + DefaultInfo(files = depset([output])), + ] + +_sqfs_package = rule( + implementation = _sqfs_package_impl, + attrs = { + "binaries": attr.label_list( + doc = "Binaries to include in the squashfs image", + mandatory = True, + cfg = "exec", + ), + "mksquashfs": attr.label( + doc = "mksquashfs executable (from @squashfs-tools//:mksquashfs)", + executable = True, + cfg = "exec", + default = Label("@squashfs-tools//:mksquashfs"), + ), + }, +) + +def sqfs_package( + name, # type: str + binaries, # type: list[label] +): + """Create a SquashFS image containing the given binaries. + + Args: + name: Target name; must end in `.sqfs`. The output file will be + named exactly `` (e.g. `echo-server.sqfs`). + binaries: List of binary labels to include in the squashfs image. + Each binary is placed at `bin/` inside the image. + """ + if name[-5:] != ".sqfs": + fail("name must end in .sqfs: {}".format(name)) + + _sqfs_package( + name = name, + binaries = binaries, + mksquashfs = "@squashfs-tools//:mksquashfs", + visibility = ["//visibility:public"], + ) -- 2.52.0