| """General utility functions""" |
| |
| def _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 |
| |
| Args: |
| tags: List of tags to filter |
| |
| Returns: |
| List of tags that only contains the well known set |
| """ |
| |
| WELL_KNOWN_TAGS = [ |
| "no-sandbox", |
| "no-cache", |
| "no-remote-cache", |
| "no-remote-exec", |
| "no-remote", |
| "local", |
| "requires-network", |
| "block-network", |
| "requires-fakeroot", |
| "exclusive", |
| "manual", |
| "external", |
| ] |
| |
| # cpu:n tags allow setting the requested number of CPUs for a test target. |
| # More info at https://docs.bazel.build/versions/main/test-encyclopedia.html#other-resources |
| CPU_PREFIX = "cpu:" |
| |
| return [ |
| tag |
| for tag in tags |
| if tag in WELL_KNOWN_TAGS or tag.startswith(CPU_PREFIX) |
| ] |
| |
| def _to_label(param): |
| """Converts a string to a Label. If Label is supplied, the same label is returned. |
| |
| Args: |
| param: a string representing a label or a Label |
| |
| Returns: |
| a Label |
| """ |
| param_type = type(param) |
| if param_type == "string": |
| if param.startswith("@"): |
| return Label(param) |
| if param.startswith("//"): |
| return Label("@" + param) |
| |
| # resolve the relative label from the current package |
| # if 'param' is in another workspace, then this would return the label relative to that workspace, eg: |
| # `Label("@my//foo:bar").relative("@other//baz:bill") == Label("@other//baz:bill")` |
| if param.startswith(":"): |
| param = param[1:] |
| if native.package_name(): |
| return Label("@//" + native.package_name()).relative(param) |
| else: |
| return Label("@//:" + param) |
| |
| elif param_type == "Label": |
| return param |
| else: |
| msg = "Expected 'string' or 'Label' but got '{}'".format(param_type) |
| fail(msg) |
| |
| def _is_external_label(param): |
| """Returns True if the given Label (or stringy version of a label) represents a target outside of the workspace |
| |
| Args: |
| param: a string or label |
| |
| Returns: |
| a bool |
| """ |
| |
| # Seems like a bug in Bazel that the workspace_root for a label like |
| # @@//js/private/node-patches:fs.js is "external" |
| # See https://github.com/bazelbuild/bazel/issues/16528 |
| #if str(param).startswith("@@//"): |
| # return False |
| return len(_to_label(param).workspace_root) > 0 |
| |
| # Path to the root of the workspace |
| def _path_to_workspace_root(): |
| """ Returns the path to the workspace root under bazel |
| |
| Returns: |
| Path to the workspace root |
| """ |
| return "/".join([".."] * len(native.package_name().split("/"))) |
| |
| # Like glob() but returns directories only |
| def _glob_directories(include, **kwargs): |
| all = native.glob(include, exclude_directories = 0, **kwargs) |
| files = native.glob(include, **kwargs) |
| directories = [p for p in all if p not in files] |
| return directories |
| |
| def _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. |
| |
| Args: |
| path: a label, or a string which is a path relative to this package |
| """ |
| label = _to_label(path) |
| file_abs = "%s/%s" % (label.package, label.name) |
| file_rel = file_abs[len(native.package_name()) + 1:] |
| file_glob = native.glob([file_rel], exclude_directories = 1) |
| return len(file_glob) > 0 |
| |
| def _default_timeout(size, timeout): |
| """Provide a sane default for *_test timeout attribute. |
| |
| The [test-encyclopedia](https://bazel.build/reference/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. |
| |
| Args: |
| size: the size attribute of a test target |
| timeout: the timeout attribute of a test target |
| |
| Returns: |
| "short" if neither is set, otherwise timeout |
| """ |
| |
| if size == None and timeout == None: |
| return "short" |
| |
| return timeout |
| |
| utils = struct( |
| is_external_label = _is_external_label, |
| file_exists = _file_exists, |
| glob_directories = _glob_directories, |
| path_to_workspace_root = _path_to_workspace_root, |
| propagate_well_known_tags = _propagate_well_known_tags, |
| to_label = _to_label, |
| default_timeout = _default_timeout, |
| ) |