bazelbuild/buildtools

repository·main·Indexed 22 days ago

https://github.com/bazelbuild/buildtools

A collection of developer tools for managing and optimizing Bazel build files. It includes Buildifier, used for formatting and linting Bazel BUILD and .bzl files, and Buildozer, a command-line tool for programmatically rewriting and refactoring multiple Bazel BUILD files using target selectors and a wide range of attribute and rule management commands.

Tokens
13.1K
Snippets
54
Records
79
Agent score
78%

What's inside buildtools

  1. Overview of Bazel buildtools

    main

    The bazelbuild/buildtools repository provides a suite of developer tools designed to improve the workflow when working with Google's bazel build system. The repository contains three primary tools:

    • buildifier: A tool for formatting BUILD, BUILD.bazel, and BUCK files to ensure they adhere to a standard style.
    • buildozer: A command-line utility for performing programmatic edits and operations on BUILD, BUILD.bazel, and BUCK files.
    • unused_deps: A tool used to identify unneeded dependencies within java_library rules.
  2. Fixing 'overly-nested-depset' performance warnings

    main

    The overly-nested-depset warning occurs when a depset is iteratively chained in a loop, which can cause performance issues.

    Avoid this pattern:

    for ...:
        x = depset(..., transitive = [..., x, ...])

    Recommended fix: Create a flat list of transitive elements first, then call the depset constructor once.

    transitive = []
    
    for ...:
        transitive += ...
    
    x = depset(..., transitive = transitive)

    Alternatively, use a list comprehension for simple cases:

    x = depset(..., transitive = [y.deps for y in ...])
    transitive = []
    
    for ...:
        transitive += ...
    
    x = depset(..., transitive = transitive)
  3. Understand Buildozer's syntax-level operation

    main

    Buildozer operates at the syntax level and does not evaluate BUILD files. This means it sees the file as it exists on disk, before any macro expansion or Bazel extensions are applied.

    If you need to see the fully expanded version of a BUILD file (the version Bazel actually uses after macros are processed), use the bazel query command instead:

    bazel query --output=build //path/to/BUILD
  4. Format function docstrings

    main

    Public functions (with at least 5 statements) should include a docstring as the first statement. Docstrings must be string literals, not comments.

    Required Format:

    1. A one-line summary.
    2. An optional blank line followed by a description.
    3. An Args: section documenting parameters (indented by 1-2 spaces).
    4. A Returns: section describing the return value.
    5. An optional Deprecated: section.
    """One-line summary.
    
    Optional description.
    
    Args:
      param1: description.
    
    Returns:
      description.
    """
  5. Use Buildozer target selectors

    main

    Buildozer uses Bazel label syntax with several special selectors to target specific parts of a BUILD file:

    • Specific Rule: //path/to/pkg:rule_name
    • Package Declaration: //path/to/pkg:__pkg__ (useful for file-level changes like new_load or new).
    • All Rules in a File: //pkg:*
    • All Descendant BUILD Files: //pkg/...:*
    • Rules of a Specific Kind: //pkg:%rule_kind (e.g., //pkg:%java_library).
    • Rule at a Specific Line: //pkg:%123 (targets the rule starting at line 123).
    • Input Stream Package: -:all_tests (reads the BUILD file from standard input instead of the local directory).
    • All Elements in a Command File: If a command file line uses the single label *, the command is applied to all labels provided on the command line.
  6. Order dictionary items by keys

    main

    The unsorted-dict-items warning (disabled by default) suggests that dictionary items should be sorted lexicographically by their keys to improve readability and reduce merge conflicts.

    Suppressing for a specific dictionary: If you need to preserve a specific order, add the # @unsorted-dict-items comment to the dictionary expression or its enclosing expression.

    Example:

    # @unsorted-dict-items
    d = {
        "b": "bvalue",
        "a": "avalue",
    }
    # @unsorted-dict-items
    d = {
        "b": "bvalue",
        "a": "avalue",
    }
  7. Avoid string iteration in Starlark

    main

    The string-iteration warning indicates that you are iterating over a string. Because of the Bazel flag --incompatible_string_is_not_iterable, strings are not recognized as sequences of 1-element strings.

    Instead of iterating over the string directly, use string indexing and len().

    Example Fix:

    my_string = "hello world"
    for i in range(len(my_string)):
        char = my_string[i]
        # do something with char
    my_string = "hello world"
    for i in range(len(my_string)):
        char = my_string[i]
  8. Follow the standard BUILD file structure

    main

    To avoid the package-on-top warning, ensure your package() declaration is near the top of the file. A typical structure is:

    1. load() statements
    2. package()
    3. Calls to rules, macros, etc.

    Allowed elements before package():

    • Comments
    • load()
    • Variable declarations
    • package_group()
    • licenses()
  9. Avoid using canonical repository names (@@ prefix)

    main

    Using canonical repository names (prefixed with @@) makes BUILD files fragile to repository mapping changes and external dependency updates. These names are internal implementation details.

    Instead of:

    load("@@rules_go//go:def.bzl", "go_library")
    deps = ["@@protobuf~5.27.0//src:message"]

    Use apparent names with a single @:

    load("@rules_go//go:def.bzl", "go_library")
    deps = ["@protobuf//src:message"]
    # buildifier: disable=canonical-repository