Project: /_project.yaml Book: /_book.yaml
{% include “_buttons.html” %}
This page covers how to create repository rules and provides examples for more details.
An external repository is a rule that can be used only in the WORKSPACE
file and enables non-hermetic operation at the loading phase of Bazel. Each external repository rule creates its own workspace, with its own BUILD
files and artifacts. They can be used to depend on third-party libraries (such as Maven packaged libraries) but also to generate BUILD
files specific to the host Bazel is running on.
In a .bzl
file, use the repository_rule function to create a new repository rule and store it in a global variable.
A custom repository rule can be used just like a native repository rule. It has a mandatory name
attribute and every target present in its build files can be referred as @<name>//package:target
where <name>
is the value of the name
attribute.
The rule is loaded when you explicitly build it, or if it is a dependency of the build. In this case, Bazel will execute its implementation
function. This function describe how to create the repository, its content and BUILD
files.
Attribute are rule arguments passed as a dict to the attrs
rule argument. The attributes and their types are defined are listed when you define a repository rule. An example definining url
and sha256
attributes as strings:
local_repository = repository_rule( implementation=_impl, local=True, attrs={ "url": attr.string(mandatory=True) "sha256": attr.string(mandatory=True) } )
To access an attribute within the implementation function, use repository_ctx.attr.<attribute_name>
:
def _impl(repository_ctx): url = repository_ctx.attr.url checksum = repository_ctx.attr.sha256
All repository_rule
s have implicitly defined attributes (just like build rules). The two implicit attributes are name
(just like for build rules) and repo_mapping
. The name of a repository rule is accessible with repository_ctx.name
. The meaning of repo_mapping
is the same as for the native repository rules local_repository
and new_local_repository
.
If an attribute name starts with _
it is private and users cannot set it.
Every repository rule requires an implementation
function. It contains the actual logic of the rule and is executed strictly in the Loading Phase.
The function has exactly one input parameter, repository_ctx
. The function returns either None
to signify that the rule is reproducible given the specified parameters, or a dict with a set of parameters for that rule that would turn that rule into a reproducible one generating the same repository. For example, for a rule tracking a git repository that would mean returning a specific commit identifier instead of a floating branch that was originally specified.
The input parameter repository_ctx
can be used to access attribute values, and non-hermetic functions (finding a binary, executing a binary, creating a file in the repository or downloading a file from the Internet). See the library for more context. Example:
def _impl(repository_ctx): repository_ctx.symlink(repository_ctx.attr.path, "") local_repository = repository_rule( implementation=_impl, ...)
The implementation function of a repository is executed when Bazel needs a target from that repository, for example when another target (in another repository) depends on it or if it is mentioned on the commmand line. The implementation function is then expected to create the repository in the file system. This is called “fetching” the repository.
In contrast to regular targets, repositories are not necessarily re-fetched when something changes that would cause the repository to be different. This is because there are things that Bazel either cannot detect changes to or it would cause too much overhead on every build (for example, things that are fetched from the network). Therefore, repositories are re-fetched only if one of the following things changes:
WORKSPACE
file.repository_ctx
's getenv()
method or declared with the environ
attribute of the repository_rule
. The values of these environment variables can be hard-wired on the command line with the --repo_env
flag.read()
, execute()
and similar methods of repository_ctx
which is referred to by a label (for example, //mypkg:label.txt
but not mypkg/label.txt
)bazel sync
is executed.There are two parameters of repository_rule
that control when the repositories are re-fetched:
If the configure
flag is set, the repository is only re-fetched on bazel sync
when the --configure
parameter is passed to it (if the attribute is unset, this command will not cause a re-fetch)
If the local
flag is set, in addition to the above cases, the repository is also re-fetched when the Bazel server restarts or when any file that affects the declaration of the repository changes (e.g. the WORKSPACE
file or a file it loads), regardless of whether the changes resulted in a change to the declaration of the repository or its code.
Non-local repositories are not re-fetched in these cases. This is because these repositories are assumed to talk to the network or be otherwise expensive.
The implementation function can be restarted while a repository is being fetched if a dependency it requests is missing. In that case, the execution of the implementation function will stop, the missing dependency is resolved and the function will be re-executed after the dependency has been resolved. To avoid unnecessary restarts (which are expensive, as network access might have to be repeated), label arguments are prefetched, provided all label arguments can be resolved to an existing file. Note that resolving a path from a string or a label that was constructed only during execution of the function might still cause a restart.
Sometimes, an external repository can become outdated without any change to its definition or dependencies. For example, a repository fetching sources might follow a particular branch of a third-party repository, and new commits are available on that branch. In this case, you can ask bazel to refetch all external repositories unconditionally by calling bazel sync
.
Moreover, some rules inspect the local machine and might become outdated if the local machine was upgraded. Here you can ask bazel to only refetch those external repositories where the repository_rule
definition has the configure
attribute set, use bazel sync --configure
.
C++ auto-configured toolchain: it uses a repository rule to automatically create the C++ configuration files for Bazel by looking for the local C++ compiler, the environment and the flags the C++ compiler supports.
Go repositories uses several repository_rule
to defines the list of dependencies needed to use the Go rules.
rules_jvm_external creates an external repository called @maven
by default that generates build targets for every Maven artifact in the transitive dependency tree.