Practical Bazel: local_archive() Workspace Rule
Practical Bazel bazel
Published: 2023-03-01
Practical Bazel: local_archive() Workspace Rule

In general, one should never check in binary artifacts into Git; it is better to retrieve them from an artifact repository or a website using http_archive(). However, sometimes convenience is more important than ideological purity. To handle these cases, I wrote a simple workspace rule named local_archive().

http_archive() is one of the most commonly used workspace rules. Besides downloading archives from HTTP, it also supports a number of other useful features such:

  • SHA256 validation of the downloaded file to prevent injection attacks
  • Automatic extraction of the contents of the archive
  • A build_file attribute which can be used to provide post-download Bazel build instructions
  • A strip_prefix attribute, to remove a common prefix from downloaded archives post-extraction

There is no equivalent to http_archive() for locally-stored archives, so I wrote a simple one. It is included below:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# //:local_archive.bzl
#
# local_archive(): A Bazel workspace rule which acts like http_archive() but
# for locally-stored archive files.
#
# Note that some features of http_archive() are not implemented, such as
# sha256 validation.
def _impl(repository_ctx):
    repository_ctx.extract(
        archive = repository_ctx.attr.src,
        stripPrefix = repository_ctx.attr.strip_prefix
    )
    repository_ctx.file(
        "BUILD.bazel",
        repository_ctx.read(repository_ctx.attr.build_file)
    )

local_archive = repository_rule(
    implementation = _impl,
    attrs = {
        "src": attr.label(mandatory = True, allow_single_file = True),
        "build_file": attr.label(mandatory = True, allow_single_file = True),
        "sha256": attr.string(),
        "strip_prefix": attr.string(),
    },
)

Use it as follows:

1
2
3
4
5
6
7
8
9
load("//:local_archive.bzl", "local_archive")

local_archive(
    name = "org_lzma_lzma",
    src = "//third_party/xz:xz-5.2.3.tar.gz",
    build_file = "@com_github_nelhage_rules_boost//:BUILD.lzma",
    sha256 = "71928b357d0a09a12a4b4c5fafca8c31c19b0e7d3b8ebb19622e96f26dbf28cb",
    strip_prefix = "xz-5.2.3",
)