| # Copyright 2019 The Bazel Authors. All rights reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| """Bazel Flags.""" |
| |
| load("//rules:utils.bzl", "utils") |
| load("//rules:visibility.bzl", "PROJECT_VISIBILITY") |
| |
| visibility(PROJECT_VISIBILITY) |
| |
| _BoolFlagInfo = provider( |
| doc = "Provides information about a boolean flag", |
| fields = dict( |
| name = "flag name", |
| value = "flag value", |
| explicit = "whether value was set explicitly", |
| ), |
| ) |
| _BoolFlagGroupInfo = provider( |
| doc = "Provides information about a boolean flag group", |
| fields = dict( |
| name = "group name", |
| value = "group value", |
| flags = "flag names that belong to this group", |
| ), |
| ) |
| _IntFlagInfo = provider( |
| doc = "Provides information about an integer flag", |
| fields = dict( |
| name = "flag name", |
| value = "flag value", |
| ), |
| ) |
| _NativeBoolFlagInfo = provider( |
| doc = "Provides information about a native boolean flag", |
| fields = dict( |
| name = "flag name, the name of the native flag being accessed.", |
| value = "flag value, derived from config_setting targets that access the value", |
| ), |
| ) |
| FlagsInfo = provider( |
| doc = "Provides all flags", |
| ) |
| |
| def _native_bool_impl(ctx): |
| return _NativeBoolFlagInfo( |
| name = ctx.label.name, |
| value = ctx.attr.value, |
| ) |
| |
| native_bool_flag = rule( |
| implementation = _native_bool_impl, |
| attrs = dict( |
| value = attr.bool(mandatory = True), |
| ), |
| provides = [_NativeBoolFlagInfo], |
| ) |
| |
| def native_bool_flag_macro(name, description): |
| """Provides access to a native boolean flag from Starlark. |
| |
| Args: |
| name: The name of the native flag to access. |
| description: The description of the flag. |
| """ |
| native.config_setting( |
| name = name + "_on", |
| values = {name: "True"}, |
| ) |
| native.config_setting( |
| name = name + "_off", |
| values = {name: "False"}, |
| ) |
| native_bool_flag( |
| name = name, |
| value = select({ |
| (":" + name + "_on"): True, |
| (":" + name + "_off"): False, |
| }), |
| ) |
| |
| def _get_bool(v): |
| v = v.lower() |
| if v == "true": |
| return True |
| if v == "false": |
| return False |
| fail("Unknown bool: " + v) |
| |
| def _bool_impl(ctx): |
| if ctx.label.name in ctx.var: |
| value = _get_bool(ctx.var[ctx.label.name]) |
| return _BoolFlagInfo( |
| name = ctx.label.name, |
| value = value, |
| explicit = True, |
| ) |
| return _BoolFlagInfo( |
| name = ctx.label.name, |
| value = ctx.attr.default, |
| explicit = False, |
| ) |
| |
| bool_flag = rule( |
| implementation = _bool_impl, |
| attrs = dict( |
| default = attr.bool( |
| mandatory = True, |
| ), |
| description = attr.string( |
| mandatory = True, |
| ), |
| ), |
| provides = [_BoolFlagInfo], |
| ) |
| |
| def _bool_group_impl(ctx): |
| if ctx.label.name in ctx.var: |
| value = _get_bool(ctx.var[ctx.label.name]) |
| return _BoolFlagGroupInfo( |
| name = ctx.label.name, |
| value = value, |
| flags = [f[_BoolFlagInfo].name for f in ctx.attr.flags], |
| ) |
| return _BoolFlagGroupInfo( |
| name = ctx.label.name, |
| value = ctx.attr.default, |
| flags = [f[_BoolFlagInfo].name for f in ctx.attr.flags], |
| ) |
| |
| bool_flag_group = rule( |
| implementation = _bool_group_impl, |
| attrs = dict( |
| default = attr.bool( |
| mandatory = True, |
| ), |
| description = attr.string( |
| mandatory = True, |
| ), |
| flags = attr.label_list( |
| mandatory = True, |
| providers = [_BoolFlagInfo], |
| ), |
| ), |
| provides = [_BoolFlagGroupInfo], |
| ) |
| |
| def _int_impl(ctx): |
| if ctx.label.name in ctx.var: |
| value = int(ctx.var[ctx.label.name]) |
| else: |
| value = ctx.attr.default |
| return _IntFlagInfo( |
| name = ctx.label.name, |
| value = value, |
| ) |
| |
| int_flag = rule( |
| implementation = _int_impl, |
| attrs = dict( |
| default = attr.int( |
| mandatory = True, |
| ), |
| description = attr.string( |
| mandatory = True, |
| ), |
| ), |
| provides = [_IntFlagInfo], |
| ) |
| |
| def _flags_impl_internal(bool_flags, bool_flag_groups, int_flags, native_bool_flags): |
| flags = dict() |
| |
| # For each group, set all flags to the group value |
| for fg in bool_flag_groups: |
| for f in fg.flags: |
| if f in flags: |
| fail("Flag '%s' referenced in multiple flag groups" % f) |
| flags[f] = fg.value |
| |
| # Set booleans |
| for b in bool_flags: |
| # Always set explicitly specified flags |
| if b.explicit: |
| flags[b.name] = b.value |
| # If not explicit, only set when not set by a group |
| |
| elif b.name not in flags: |
| flags[b.name] = b.value |
| |
| # Set ints |
| for i in int_flags: |
| flags[i.name] = i.value |
| |
| # Set native bool flags |
| for n in native_bool_flags: |
| if n.name in flags: |
| fail("Flag '%s' defined as both native and non-native flag type" % n.name) |
| flags[n.name] = n.value |
| |
| return FlagsInfo(**flags) |
| |
| def _flags_impl(ctx): |
| return _flags_impl_internal( |
| utils.collect_providers(_BoolFlagInfo, ctx.attr.targets), |
| utils.collect_providers(_BoolFlagGroupInfo, ctx.attr.targets), |
| utils.collect_providers(_IntFlagInfo, ctx.attr.targets), |
| utils.collect_providers(_NativeBoolFlagInfo, ctx.attr.targets), |
| ) |
| |
| flags_rule = rule( |
| implementation = _flags_impl, |
| attrs = dict( |
| targets = attr.label_list(), |
| ), |
| ) |
| |
| def _flags_macro(): |
| flags_rule( |
| name = "flags", |
| targets = native.existing_rules().keys(), |
| visibility = ["//visibility:public"], |
| ) |
| |
| def _get_flags(ctx): |
| flags = ctx.attr._flags |
| if type(flags) != "list": |
| return flags[FlagsInfo] |
| return flags[0][FlagsInfo] |
| |
| flags = struct( |
| DEFINE_bool = bool_flag, |
| DEFINE_bool_group = bool_flag_group, |
| DEFINE_int = int_flag, |
| EXPOSE_native_bool = native_bool_flag_macro, |
| FLAGS = _flags_macro, |
| FlagsInfo = FlagsInfo, |
| get = _get_flags, |
| ) |
| |
| exported_for_test = struct( |
| BoolFlagGroupInfo = _BoolFlagGroupInfo, |
| BoolFlagInfo = _BoolFlagInfo, |
| IntFlagInfo = _IntFlagInfo, |
| NativeBoolFlagInfo = _NativeBoolFlagInfo, |
| bool_impl = _bool_impl, |
| flags_impl_internal = _flags_impl_internal, |
| int_impl = _int_impl, |
| native_bool_flag_macro = native_bool_flag_macro, |
| ) |