tree: 2a80e52878f2b258d2e8400b539456b163200ef0
  1. autogazelle.bash
  2. BUILD.bazel
  3. client_unix.go
  4. main.go
  5. README.md
  6. server_unix.go
cmd/autogazelle/README.md

Autogazelle: fast, automatic build file generation

Autogazelle is a wrapper program that runs Gazelle as part of each Bazel command. You can add, delete, or rename source files, add imports, then just bazel build. Your build files are updated automatically during the build.

Autogazelle is highly experimental and may change significantly in the future. Use with caution. See Limitations below.

Setting up autogazelle

Before you begin

Make sure the bazel_gazelle repository is declared in your WORKSPACE. It should look the the snippet below, but the versions will likely be different. It may be possible to used Autogazelle from a vendored bazel_gazelle repository, but this is not directly supported yet.

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

http_archive(
    name = "io_bazel_rules_go",
    integrity = "sha256-fHbWI2so/2laoozzX5XeMXqUcv0fsUrHl8m/aE8Js3w=",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.44.2/rules_go-v0.44.2.zip",
        "https://github.com/bazelbuild/rules_go/releases/download/v0.44.2/rules_go-v0.44.2.zip",
    ],
)

http_archive(
    name = "bazel_gazelle",
    integrity = "sha256-MpOL2hbmcABjA1R5Bj2dJMYO2o15/Uc5Vj9Q0zHLMgk=",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.35.0/bazel-gazelle-v0.35.0.tar.gz",
        "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.35.0/bazel-gazelle-v0.35.0.tar.gz",
    ],
)

load("@io_bazel_rules_go//go:def.bzl", "go_rules_dependencies", "go_register_toolchains")
go_rules_dependencies()
go_register_toolchains()
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
gazelle_dependencies()

Make sure you have a gazelle rule declared in your root build file. It should look this this, probably with different options.

load("@bazel_gazelle//:def.bzl", "gazelle")

# gazelle:prefix github.com/example/project
gazelle(name = "gazelle")

Installing the wrapper

In order to run autogazelle as part of each Bazel command, you‘ll need to copy cmd/autogazelle/autogazelle.bash to tools/bazel within your repository. Make sure the script is executable. The bazel script in your PATH will execute this script instead of the real bazel binary if it’s present and executable.

Deleting build files

If your build files are completely generated by Gazelle, you may want to delete them from source control, since they can be easily regenerated. When Gazelle generates new files, it names them BUILD.bazel by default, so you can add BUILD.bazel to your .gitignore file after deleting them.

It‘s likely that you’ll have some build files with manual modifications you want to keep around. At minimum, you'll need to keep the root build file since it contains the gazelle rule. The simplest way to keep these files is to name the BUILD instead of BUILD.bazel. Bazel and Gazelle will both recognize files named BUILD, and Git will not ignore them.

Another option is to name your files BUILD.bazel.in or BUILD.in. Autogazelle will copy these files to BUILD.bazel or BUILD when it starts running before invoking Gazelle.

How autogazelle works

Autogazelle has three components: a wrapper script, a client, and a server.

The wrapper script is a bash script installed in tools/bazel in workspaces that use autogazelle. The bazel command installed in your PATH will look for an executable file at this location and will execute it instead of the real bazel. The script builds and runs the autogazelle client using bazel run before invoking the real bazel binary with the original command-line arguments.

The client is a Go program that attempts to connect to the server over a UNIX domain socket. If the server isn't running, the client will start it and connect. Once connected, the client will wait for the server to disconnect before exiting. The client does no other work.

The server is a Go program (actually the same binary as the client, started with different options) that listens for connections on a UNIX domain socket. When it accepts a connection, it runs Gazelle using bazel run, then closes the connection. The socket is just used to make the client wait until Gazelle completes; no information is exchanged, other than log messages. While the server is waiting for a connection, it watches the file system for changes that could affect build files. When the server runs Gazelle, it runs only in directories that have changed. This makes Gazelle run much faster. The server exits after being idle for an hour.

Limitations

Dependency resolution

Autogazelle tries to run Gazelle quickly by only updating certain directories. To support this, it runs Gazelle with the flags -r=false (don‘t recurse through selected directories) and -index=false (don’t build an index of library targets for dependency resolution). This means that you‘ll need to set external = "vendored" explicitly on your gazelle rule if you have a vendor directory, and you’ll need to add # gazelle:resolve directives in your root build files for any imports that should be resolved to custom names.

Platform support

Autogazelle uses UNIX-domain sockets to synchronize the client and server. This only works on UNIX-like platforms; these sockets are not supported on Windows.

Autogazelle uses github.com/fsnotify/fsnotify to watch the file system. This library works on multiple platforms, but it won‘t work on file systems that don’t support watches (e.g., NFS and most other network file systems).

Autogazelle has only been tested on Linux. It is intended to work on macOS, but this has not been tested yet.

Credits

The original idea for running Gazelle automatically was proposed by Matthew Moore (@mattmoor). The initial plan was to run Gazelle in a repository rule which regenerate a repository full of build files on each run.

Erick Fejta (@fejta) prototyped this idea for Kubernetes. You can find the prototype at https://github.com/kubernetes/test-infra/tree/master/autogo.