Gazelle started out as a build file generator for Go projects, but it can be extended to support other languages and custom sets of rules.
To extend Gazelle, you must do three things:
- Write a go_library with a function named
NewLanguage
that provides an implementation of the Language interface. This interface provides hooks for generating rules, parsing configuration directives, and resolving imports to Bazel labels. By convention, the library's package name should match the language (for example,proto
orbzl
). - Write a gazelle_binary rule. Include your library in the
languages
list. - Write a gazelle rule that points to your
gazelle_binary
. When you runbazel run //:gazelle
, your binary will be built and executed instead of the default binary.
To write tests for your gazelle extension, you can use gazelle_generation_test, which will run a gazelle binary of your choosing on a set of test workspaces.
Moved to /README.rst
Gazelle itself is built using the model described above, so it may serve as an example.
//language/proto:go_default_library and //language/go:go_default_library both implement the Language interface. There is also //internal/gazellebinarytest:go_default_library, a stub implementation used for testing.
//cmd/gazelle
is a gazelle_binary
rule that includes both of these
libraries through the DEFAULT_LANGUAGES
list (you may want to use
DEFAULT_LANGUAGES
in your own rule).
load("@bazel_gazelle//:def.bzl", "DEFAULT_LANGUAGES", "gazelle_binary")
gazelle_binary(
name = "gazelle",
languages = [
"@rules_python//gazelle", # Use gazelle from rules_python.
"@bazel_gazelle//language/go", # Built-in rule from gazelle for Golang.
"@bazel_gazelle//language/proto", # Built-in rule from gazelle for Protos.
# Any languages that depend on Gazelle's proto plugin must come after it.
"@external_repository//language/gazelle", # External languages can be added here.
],
visibility = ["//visibility:public"],
)
This binary can be invoked using a gazelle
rule like this:
load("@bazel_gazelle//:def.bzl", "gazelle")
# gazelle:prefix example.com/project
gazelle(
name = "gazelle",
gazelle = "//:my_gazelle_binary",
)
You can run this with bazel run //:gazelle
.
The proto extension (//language/proto:go_default_library) gathers metadata
from .proto files and generates proto_library
rules based on that metadata.
Extensions that generate language-specific proto rules (e.g.,
go_proto_library
) may use this metadata.
For API reference, see the proto godoc.
To get proto configuration information, call proto.GetProtoConfig. This is mainly useful for discovering the current proto mode.
To get information about proto_library
rules, examine the OtherGen
list of rules passed to language.GenerateRules
. This is a list of rules
generated by other language extensions, and it will include proto_library
rules in each directory, if there were any. For each of these rules, you can
call r.PrivateAttr(proto.PackageKey)
to get a proto.Package record. This
includes the proto package name, as well as source names, imports, and options.
gazelle_binary(name, languages)
The gazelle_binary
rule builds a Go binary that incorporates a list of
language extensions. This requires generating a small amount of code that
must be compiled into Gazelle's main package, so the normal go_binary
rule is not used.
When the binary runs, each language extension is run sequentially. This affects
the order that rules appear in generated build files. Metadata may be produced
by an earlier extension and consumed by a later extension. For example, the
proto extension stores metadata in hidden attributes of generated
proto_library
rules. The Go extension uses this metadata to generate
go_proto_library
rules.
ATTRIBUTES
Name | Description | Type | Mandatory | Default |
---|---|---|---|---|
name | A unique name for this target. | Name | required | |
languages | A list of language extensions the Gazelle binary will use. Each extension must be a go_library or something compatible. Each extension must export a function named NewLanguage with no parameters that returns a value assignable to Language. |
List of labels | required |
gazelle_generation_test(name, gazelle_binary, test_data, build_in_suffix, build_out_suffix, gazelle_timeout_seconds, size, kwargs)
gazelle_generation_test is a macro for testing gazelle against workspaces.
The generation test expects a file structure like the following:
|-- <testDataPath>
|-- some_test
|-- WORKSPACE and/or MODULE.bazel -> Indicates the directory is a test case.
|-- README.md --> README describing what the test does.
|-- arguments.txt --> newline delimited list of arguments to pass in (ignored if empty).
|-- expectedStdout.txt --> Expected stdout for this test.
|-- expectedStderr.txt --> Expected stderr for this test.
|-- expectedExitCode.txt --> Expected exit code for this test.
|-- app
|-- sourceFile.foo
|-- BUILD.in --> BUILD file prior to running gazelle.
|-- BUILD.out --> BUILD file expected after running gazelle.
To update the expected files, run UPDATE_SNAPSHOTS=true bazel run //path/to:the_test_target
.
PARAMETERS
Name | Description | Default Value |
---|---|---|
name | The name of the test. | none |
gazelle_binary | The name of the gazelle binary target. For example, //path/to:my_gazelle. | none |
test_data | A list of target of the test data files you will pass to the test. This can be a https://bazel.build/reference/be/general#filegroup. | none |
build_in_suffix | The suffix for the input BUILD.bazel files. Defaults to .in. By default, will use files named BUILD.in as the BUILD files before running gazelle. | ".in" |
build_out_suffix | The suffix for the expected BUILD.bazel files after running gazelle. Defaults to .out. By default, will use files named check the results of the gazelle run against files named BUILD.out. | ".out" |
gazelle_timeout_seconds | Number of seconds to allow the gazelle process to run before killing. | 2 |
size | Specifies a test target's "heaviness": how much time/resources it needs to run. | None |
kwargs | Attributes that are passed directly to the test declaration. | none |