| # Protocol Buffers - Google's data interchange format |
| # Copyright 2008 Google Inc. All rights reserved. |
| # |
| # Use of this source code is governed by a BSD-style |
| # license that can be found in the LICENSE file or at |
| # https://developers.google.com/open-source/licenses/bsd |
| """Helper rules and macros for custom proto flags.""" |
| |
| load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo") |
| load("//bazel/private:native.bzl", "HAS_NATIVE_PROTO_FLAGS") |
| |
| def _compat_bool_rule_impl(ctx): |
| starlark_val = ctx.build_setting_value |
| |
| # 1. Starlark flag takes precedence if explicitly passed (not "default") |
| if starlark_val != "default": |
| if starlark_val in ctx.attr.true_values: |
| return [BuildSettingInfo(value = True)] |
| if starlark_val in ctx.attr.false_values: |
| return [BuildSettingInfo(value = False)] |
| allowed = ctx.attr.true_values + ctx.attr.false_values + ["default"] |
| fail("Invalid value '%s' for flag %s. Allowed values are: %s" % ( |
| starlark_val, |
| ctx.label, |
| allowed, |
| )) |
| |
| # 2. Native flag fallback (if HAS_NATIVE_PROTO_FLAGS and present on ctx.fragments.proto) |
| if HAS_NATIVE_PROTO_FLAGS and hasattr(ctx.fragments, "proto") and ctx.attr.fragment_field: |
| if hasattr(ctx.fragments.proto, ctx.attr.fragment_field): |
| native_val = getattr(ctx.fragments.proto, ctx.attr.fragment_field)() |
| if native_val == True or native_val in ctx.attr.true_values: |
| return [BuildSettingInfo(value = True)] |
| if native_val == False or native_val in ctx.attr.false_values: |
| return [BuildSettingInfo(value = False)] |
| |
| # 3. Default fallback |
| return [BuildSettingInfo(value = ctx.attr.default_value)] |
| |
| _compat_bool_rule = rule( |
| implementation = _compat_bool_rule_impl, |
| build_setting = config.string(flag = True), |
| fragments = ["proto"] if HAS_NATIVE_PROTO_FLAGS else [], |
| attrs = { |
| "fragment_field": attr.string(), |
| "true_values": attr.string_list(default = []), |
| "false_values": attr.string_list(default = []), |
| "default_value": attr.bool(default = False), |
| "scope": attr.string(), |
| }, |
| ) |
| |
| def compat_bool_flag( |
| *, |
| name, |
| fragment_field = None, |
| build_setting_default = False, |
| values = None, |
| **kwargs): |
| """Creates a custom build setting flag reconciling Starlark/fragments. |
| |
| Args: |
| name: The target name for the Starlark build setting flag. |
| fragment_field: The field name in ctx.fragments.proto (e.g. "strict_proto_deps"), if any. |
| build_setting_default: Fallback default boolean value if neither Starlark nor fragment is set. |
| values: Dict mapping booleans (True/False) to lists of accepted string flag values. |
| Defaults to {True: ["true", "TRUE", "1"], False: ["false", "FALSE", "0"]}. |
| **kwargs: Additional rule arguments (such as `scope`). |
| """ |
| if values == None: |
| values = { |
| True: ["true", "TRUE", "1"], |
| False: ["false", "FALSE", "0"], |
| } |
| |
| true_vals = values.get(True, []) |
| false_vals = values.get(False, []) |
| |
| starlark_true_vals = [v for v in true_vals if v != "default"] |
| starlark_false_vals = [v for v in false_vals if v != "default"] |
| |
| _compat_bool_rule( |
| name = name, |
| build_setting_default = "default", |
| fragment_field = fragment_field, |
| true_values = starlark_true_vals, |
| false_values = starlark_false_vals, |
| default_value = build_setting_default, |
| **kwargs |
| ) |
| |
| def _compat_string_list_rule_impl(ctx): |
| starlark_val = ctx.build_setting_value |
| if starlark_val: |
| return [BuildSettingInfo(value = starlark_val)] |
| if HAS_NATIVE_PROTO_FLAGS and hasattr(ctx.fragments, "proto") and ctx.attr.fragment_field: |
| if hasattr(ctx.fragments.proto, ctx.attr.fragment_field): |
| val = getattr(ctx.fragments.proto, ctx.attr.fragment_field) |
| return [BuildSettingInfo(value = val)] |
| return [BuildSettingInfo(value = ctx.attr.default_value)] |
| |
| _compat_string_list_rule = rule( |
| implementation = _compat_string_list_rule_impl, |
| build_setting = config.string_list(flag = True, repeatable = True), |
| fragments = ["proto"] if HAS_NATIVE_PROTO_FLAGS else [], |
| attrs = { |
| "fragment_field": attr.string(), |
| "default_value": attr.string_list(default = []), |
| "scope": attr.string(), |
| }, |
| ) |
| |
| def compat_string_list_flag( |
| *, |
| name, |
| fragment_field = None, |
| build_setting_default = None, |
| **kwargs): |
| """Creates a custom string-list build setting reconciling Starlark/fragments. |
| |
| Args: |
| name: The target name for the Starlark build setting flag. |
| fragment_field: The field name in ctx.fragments.proto (e.g. "experimental_protoc_opts"), if any. |
| build_setting_default: Fallback default string list value if neither Starlark nor fragment is set. |
| **kwargs: Additional rule arguments (such as `scope`). |
| """ |
| default_vals = build_setting_default if build_setting_default != None else [] |
| |
| _compat_string_list_rule( |
| name = name, |
| build_setting_default = default_vals, |
| fragment_field = fragment_field, |
| default_value = default_vals, |
| **kwargs |
| ) |