How to create a directory structure in bazel

5.4k Views Asked by At

I want to create the following structure in bazel.

dir1
   |_ file1
   |_ file2
   |_ dir2
         |_file3

Creating a specific structure doesn't seem trivial. I'm hoping there's a simple and reusable rule. Something like:

makedir(
  name = "dir1",
  path = "dir1",
)

makedir(
  name = "dir2",
  path = "dir1/dir2",
  deps = [":dir1"],
)

What I've tried:

  • I could create a macro with a python script, but want something cleaner.
  • I tried creating a genrule with mkdir -p path/to/directoy which didn't work

The use case is that I want to create a squashfs using bazel.

It's important to note that Bazel provides some packaging functions.

To create a squashfs, the command requires a directory structure populated with artifacts.

3

There are 3 best solutions below

0
On BEST ANSWER

In my case, I want to create a directory structure and run mksquashfs to produce a squashfs file.

To accomplish this, I ended up modifying the basic example from bazel's docs on packaging.

load("@bazel_tools//tools/build_defs/pkg:pkg.bzl", "pkg_tar")

genrule(
    name = "file1",
    outs = ["file1.txt"],
    cmd = "echo exampleText > $@",
)

pkg_tar(
    name = "dir1",
    strip_prefix = ".",
    package_dir = "/usr/bin",
    srcs = [":file1"],
    mode = "0755",
)

pkg_tar(
    name = "dir2",
    strip_prefix = ".",
    package_dir = "/usr/share",
    srcs = ["//main:file2.txt", "//main:file3.txt"],
    mode = "0644",
)

pkg_tar(
    name = "pkg",
    extension = "tar.gz",
    deps = [
        ":dir1",
        ":dir2",
    ],
)

If there's an easier way to create a tar or directory structure without the need for intermediate tars, I'll make that top answer.

1
On

You can always create a genrule target or a shell_binary target that will execute bash command or a shell script (respectively) that creates these directories.

with genrule you can use bazel's $(location) that will make sure that the dir structure you create will be under an output path that is inside bazel's sandbox environment. The genrule example shows how to use it exactly.

Here you can find more details on predefined output paths.

0
On

You could create such a Bazel macro, that uses genrule:

def mkdir(name, out_dir, marker_file = "marker"):
    """Create an empty directory that you can use as an input in another rule

    This will technically create an empty marker file in that directory to avoid Bazel warnings.
    You should depend on this marker file.
    """
    path = "%s/%s" % (out_dir, marker_file)
    native.genrule(
        name = name,
        outs = [path],
        cmd = """mkdir -p $$(dirname $(location :%s)) && touch $(location :%s)""" % (path, path),
    )

Then you can use the outputs generated by this macro in a pkg_tar definition:

mkdir(
    name = "generate_a_dir",
    out_dir = "my_dir",
)

pkg_tar(
    name = "package",
    srcs = [
        # ...
        ":generate_a_dir",
    ],
    # ...
)