bazel-lib/docs/utils.md

23 KiB

General-purpose Starlark utility functions

Usage example

load("@aspect_bazel_lib//lib:utils.bzl", "utils")

out_label = utils.to_label(out_file)

consistent_label_str

consistent_label_str(ctx, label)

Generate a consistent label string for all Bazel versions.

Starting in Bazel 6, the workspace name is empty for the local workspace and there's no other way to determine it. This behavior differs from Bazel 5 where the local workspace name was fully qualified in str(label).

This utility function is meant for use in rules and requires the rule context to determine the user's workspace name (ctx.workspace_name).

PARAMETERS

Name Description Default Value
ctx The rule context. none
label A Label. none

RETURNS

String representation of the label including the repository name if the label is from an external repository. For labels in the user's repository the label will start with @//.

default_timeout

default_timeout(size, timeout)

Provide a sane default for *_test timeout attribute.

The test-encyclopedia says:

Tests may return arbitrarily fast regardless of timeout. A test is not penalized for an overgenerous timeout, although a warning may be issued: you should generally set your timeout as tight as you can without incurring any flakiness.

However Bazel's default for timeout is medium, which is dumb given this guidance.

It also says:

Tests which do not explicitly specify a timeout have one implied based on the test's size as follows

Therefore if size is specified, we should allow timeout to take its implied default. If neither is set, then we can fix Bazel's wrong default here to avoid warnings under --test_verbose_timeout_warnings.

This function can be used in a macro which wraps a testing rule.

PARAMETERS

Name Description Default Value
size the size attribute of a test target none
timeout the timeout attribute of a test target none

RETURNS

"short" if neither is set, otherwise timeout

file_exists

file_exists(path)

Check whether a file exists.

Useful in macros to set defaults for a configuration file if it is present. This can only be called during the loading phase, not from a rule implementation.

PARAMETERS

Name Description Default Value
path a label, or a string which is a path relative to this package none

glob_directories

glob_directories(include, kwargs)

PARAMETERS

Name Description Default Value
include

-

none
kwargs

-

none

is_bazel_6_or_greater

is_bazel_6_or_greater()

Detects if the Bazel version being used is greater than or equal to 6 (including Bazel 6 pre-releases and RCs).

Detecting Bazel 6 or greater is particularly useful in rules as slightly different code paths may be needed to support bzlmod which was added in Bazel 6.

Unlike the undocumented native.bazel_version, which only works in WORKSPACE and repository rules, this function can be used in rules and BUILD files.

An alternate approach to make the Bazel version available in BUILD files and rules would be to use the host_repo repository rule which contains the bazel_version in the exported host struct:

WORKSPACE:

load("@aspect_bazel_lib//lib:host_repo.bzl", "host_repo")
host_repo(name = "aspect_bazel_lib_host")

BUILD.bazel:

load("@aspect_bazel_lib_host//:defs.bzl", "host")
print(host.bazel_version)

That approach, however, incurs a cost in the user's WORKSPACE.

RETURNS

True if the Bazel version being used is greater than or equal to 6 (including pre-releases and RCs)

is_bazel_7_or_greater

is_bazel_7_or_greater()

Detects if the Bazel version being used is greater than or equal to 7 (including Bazel 7 pre-releases and RCs).

Unlike the undocumented native.bazel_version, which only works in WORKSPACE and repository rules, this function can be used in rules and BUILD files.

An alternate approach to make the Bazel version available in BUILD files and rules would be to use the host_repo repository rule which contains the bazel_version in the exported host struct:

WORKSPACE:

load("@aspect_bazel_lib//lib:host_repo.bzl", "host_repo")
host_repo(name = "aspect_bazel_lib_host")

BUILD.bazel:

load("@aspect_bazel_lib_host//:defs.bzl", "host")
print(host.bazel_version)

That approach, however, incurs a cost in the user's WORKSPACE.

RETURNS

True if the Bazel version being used is greater than or equal to 7 (including pre-releases and RCs)

is_bzlmod_enabled

is_bzlmod_enabled()

Detect the value of the --enable_bzlmod flag

is_external_label

is_external_label(param)

Returns True if the given Label (or stringy version of a label) represents a target outside of the workspace

PARAMETERS

Name Description Default Value
param a string or label none

RETURNS

a bool

maybe_http_archive

maybe_http_archive(kwargs)

Adapts a maybe(http_archive, ...) to look like an http_archive.

This makes WORKSPACE dependencies easier to read and update.

Typical usage looks like,

load("//lib:utils.bzl", http_archive = "maybe_http_archive")

http_archive(
    name = "aspect_rules_js",
    sha256 = "5bb643d9e119832a383e67f946dc752b6d719d66d1df9b46d840509ceb53e1f1",
    strip_prefix = "rules_js-1.6.2",
    url = "https://github.com/aspect-build/rules_js/archive/refs/tags/v1.6.2.tar.gz",
)

instead of the classic maybe pattern of,

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

maybe(
    http_archive,
    name = "aspect_rules_js",
    sha256 = "5bb643d9e119832a383e67f946dc752b6d719d66d1df9b46d840509ceb53e1f1",
    strip_prefix = "rules_js-1.6.2",
    url = "https://github.com/aspect-build/rules_js/archive/refs/tags/v1.6.2.tar.gz",
)

PARAMETERS

Name Description Default Value
kwargs all arguments to pass-forward to http_archive none

path_to_workspace_root

path_to_workspace_root()

Returns the path to the workspace root under bazel

RETURNS

Path to the workspace root

propagate_common_binary_rule_attributes

propagate_common_binary_rule_attributes(attrs)

Returns a dict of rule parameters filtered from the input dict that only contains the ones that are common to all binary rules

These are listed in Bazel's documentation: https://bazel.build/reference/be/common-definitions#common-attributes https://bazel.build/reference/be/common-definitions#common-attributes-binary

PARAMETERS

Name Description Default Value
attrs Dict of parameters to filter none

RETURNS

The dict of parameters, containing only common binary attributes

propagate_common_rule_attributes

propagate_common_rule_attributes(attrs)

Returns a dict of rule parameters filtered from the input dict that only contains the ones that are common to all rules

These are listed in Bazel's documentation: https://bazel.build/reference/be/common-definitions#common-attributes

PARAMETERS

Name Description Default Value
attrs Dict of parameters to filter none

RETURNS

The dict of parameters, containing only common attributes

propagate_common_test_rule_attributes

propagate_common_test_rule_attributes(attrs)

Returns a dict of rule parameters filtered from the input dict that only contains the ones that are common to all test rules

These are listed in Bazel's documentation: https://bazel.build/reference/be/common-definitions#common-attributes https://bazel.build/reference/be/common-definitions#common-attributes-tests

PARAMETERS

Name Description Default Value
attrs Dict of parameters to filter none

RETURNS

The dict of parameters, containing only common test attributes

propagate_well_known_tags

propagate_well_known_tags(tags)

Returns a list of tags filtered from the input set that only contains the ones that are considered "well known"

These are listed in Bazel's documentation: https://docs.bazel.build/versions/main/test-encyclopedia.html#tag-conventions https://docs.bazel.build/versions/main/be/common-definitions.html#common-attributes

PARAMETERS

Name Description Default Value
tags List of tags to filter []

RETURNS

List of tags that only contains the well known set

to_label

to_label(param)

Converts a string to a Label. If Label is supplied, the same label is returned.

PARAMETERS

Name Description Default Value
param a string representing a label or a Label none

RETURNS

a Label

utils.consistent_label_str

utils.consistent_label_str(ctx, label)

Generate a consistent label string for all Bazel versions.

Starting in Bazel 6, the workspace name is empty for the local workspace and there's no other way to determine it. This behavior differs from Bazel 5 where the local workspace name was fully qualified in str(label).

This utility function is meant for use in rules and requires the rule context to determine the user's workspace name (ctx.workspace_name).

PARAMETERS

Name Description Default Value
ctx The rule context. none
label A Label. none

RETURNS

String representation of the label including the repository name if the label is from an external repository. For labels in the user's repository the label will start with @//.

utils.default_timeout

utils.default_timeout(size, timeout)

Provide a sane default for *_test timeout attribute.

The test-encyclopedia says:

Tests may return arbitrarily fast regardless of timeout. A test is not penalized for an overgenerous timeout, although a warning may be issued: you should generally set your timeout as tight as you can without incurring any flakiness.

However Bazel's default for timeout is medium, which is dumb given this guidance.

It also says:

Tests which do not explicitly specify a timeout have one implied based on the test's size as follows

Therefore if size is specified, we should allow timeout to take its implied default. If neither is set, then we can fix Bazel's wrong default here to avoid warnings under --test_verbose_timeout_warnings.

This function can be used in a macro which wraps a testing rule.

PARAMETERS

Name Description Default Value
size the size attribute of a test target none
timeout the timeout attribute of a test target none

RETURNS

"short" if neither is set, otherwise timeout

utils.file_exists

utils.file_exists(path)

Check whether a file exists.

Useful in macros to set defaults for a configuration file if it is present. This can only be called during the loading phase, not from a rule implementation.

PARAMETERS

Name Description Default Value
path a label, or a string which is a path relative to this package none

utils.glob_directories

utils.glob_directories(include, kwargs)

PARAMETERS

Name Description Default Value
include

-

none
kwargs

-

none

utils.is_bazel_6_or_greater

utils.is_bazel_6_or_greater()

Detects if the Bazel version being used is greater than or equal to 6 (including Bazel 6 pre-releases and RCs).

Detecting Bazel 6 or greater is particularly useful in rules as slightly different code paths may be needed to support bzlmod which was added in Bazel 6.

Unlike the undocumented native.bazel_version, which only works in WORKSPACE and repository rules, this function can be used in rules and BUILD files.

An alternate approach to make the Bazel version available in BUILD files and rules would be to use the host_repo repository rule which contains the bazel_version in the exported host struct:

WORKSPACE:

load("@aspect_bazel_lib//lib:host_repo.bzl", "host_repo")
host_repo(name = "aspect_bazel_lib_host")

BUILD.bazel:

load("@aspect_bazel_lib_host//:defs.bzl", "host")
print(host.bazel_version)

That approach, however, incurs a cost in the user's WORKSPACE.

RETURNS

True if the Bazel version being used is greater than or equal to 6 (including pre-releases and RCs)

utils.is_bazel_7_or_greater

utils.is_bazel_7_or_greater()

Detects if the Bazel version being used is greater than or equal to 7 (including Bazel 7 pre-releases and RCs).

Unlike the undocumented native.bazel_version, which only works in WORKSPACE and repository rules, this function can be used in rules and BUILD files.

An alternate approach to make the Bazel version available in BUILD files and rules would be to use the host_repo repository rule which contains the bazel_version in the exported host struct:

WORKSPACE:

load("@aspect_bazel_lib//lib:host_repo.bzl", "host_repo")
host_repo(name = "aspect_bazel_lib_host")

BUILD.bazel:

load("@aspect_bazel_lib_host//:defs.bzl", "host")
print(host.bazel_version)

That approach, however, incurs a cost in the user's WORKSPACE.

RETURNS

True if the Bazel version being used is greater than or equal to 7 (including pre-releases and RCs)

utils.is_bzlmod_enabled

utils.is_bzlmod_enabled()

Detect the value of the --enable_bzlmod flag

utils.is_external_label

utils.is_external_label(param)

Returns True if the given Label (or stringy version of a label) represents a target outside of the workspace

PARAMETERS

Name Description Default Value
param a string or label none

RETURNS

a bool

utils.maybe_http_archive

utils.maybe_http_archive(kwargs)

Adapts a maybe(http_archive, ...) to look like an http_archive.

This makes WORKSPACE dependencies easier to read and update.

Typical usage looks like,

load("//lib:utils.bzl", http_archive = "maybe_http_archive")

http_archive(
    name = "aspect_rules_js",
    sha256 = "5bb643d9e119832a383e67f946dc752b6d719d66d1df9b46d840509ceb53e1f1",
    strip_prefix = "rules_js-1.6.2",
    url = "https://github.com/aspect-build/rules_js/archive/refs/tags/v1.6.2.tar.gz",
)

instead of the classic maybe pattern of,

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

maybe(
    http_archive,
    name = "aspect_rules_js",
    sha256 = "5bb643d9e119832a383e67f946dc752b6d719d66d1df9b46d840509ceb53e1f1",
    strip_prefix = "rules_js-1.6.2",
    url = "https://github.com/aspect-build/rules_js/archive/refs/tags/v1.6.2.tar.gz",
)

PARAMETERS

Name Description Default Value
kwargs all arguments to pass-forward to http_archive none

utils.path_to_workspace_root

utils.path_to_workspace_root()

Returns the path to the workspace root under bazel

RETURNS

Path to the workspace root

utils.propagate_common_binary_rule_attributes

utils.propagate_common_binary_rule_attributes(attrs)

Returns a dict of rule parameters filtered from the input dict that only contains the ones that are common to all binary rules

These are listed in Bazel's documentation: https://bazel.build/reference/be/common-definitions#common-attributes https://bazel.build/reference/be/common-definitions#common-attributes-binary

PARAMETERS

Name Description Default Value
attrs Dict of parameters to filter none

RETURNS

The dict of parameters, containing only common binary attributes

utils.propagate_common_rule_attributes

utils.propagate_common_rule_attributes(attrs)

Returns a dict of rule parameters filtered from the input dict that only contains the ones that are common to all rules

These are listed in Bazel's documentation: https://bazel.build/reference/be/common-definitions#common-attributes

PARAMETERS

Name Description Default Value
attrs Dict of parameters to filter none

RETURNS

The dict of parameters, containing only common attributes

utils.propagate_common_test_rule_attributes

utils.propagate_common_test_rule_attributes(attrs)

Returns a dict of rule parameters filtered from the input dict that only contains the ones that are common to all test rules

These are listed in Bazel's documentation: https://bazel.build/reference/be/common-definitions#common-attributes https://bazel.build/reference/be/common-definitions#common-attributes-tests

PARAMETERS

Name Description Default Value
attrs Dict of parameters to filter none

RETURNS

The dict of parameters, containing only common test attributes

utils.propagate_well_known_tags

utils.propagate_well_known_tags(tags)

Returns a list of tags filtered from the input set that only contains the ones that are considered "well known"

These are listed in Bazel's documentation: https://docs.bazel.build/versions/main/test-encyclopedia.html#tag-conventions https://docs.bazel.build/versions/main/be/common-definitions.html#common-attributes

PARAMETERS

Name Description Default Value
tags List of tags to filter []

RETURNS

List of tags that only contains the well known set

utils.to_label

utils.to_label(param)

Converts a string to a Label. If Label is supplied, the same label is returned.

PARAMETERS

Name Description Default Value
param a string representing a label or a Label none

RETURNS

a Label