]> go.fuhry.dev Git - runtime.git/commitdiff
[bazel] add sqfs_package rule
authorDan Fuhry <dan@fuhry.com>
Mon, 19 Oct 2026 21:10:11 +0000 (17:10 -0400)
committerDan Fuhry <dan@fuhry.com>
Mon, 19 Oct 2026 21:28:39 +0000 (17:28 -0400)
bazel/sqfs.bzl [new file with mode: 0644]

diff --git a/bazel/sqfs.bzl b/bazel/sqfs.bzl
new file mode 100644 (file)
index 0000000..2c7fead
--- /dev/null
@@ -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/<basename> 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 `<name>` (e.g. `echo-server.sqfs`).
+        binaries: List of binary labels to include in the squashfs image.
+                  Each binary is placed at `bin/<basename>` 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"],
+    )