1# Copyright 2022 Google LLC. All rights reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the License); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""A rule for declaring and passing kotlinc opts in a restricted way. 16 17It is a goal for rules_kotlin that Kotlin libraries use consistent default compiler 18options across as much of the repo as possible. Doing so makes Kotlin easier to 19maintain at scale. 20 21If an exception needs to be made for some library, `kt_compiler_opt` can be used to 22declare a set of additional options with restricted visibility. That target can then 23be passed to the `custom_kotlincopts` attribute. The set of directories that allow 24`kt_compiler_opt` targets is also limited, to prevent misuse. 25""" 26 27load("//bazel:stubs.bzl", "check_compiler_opt_allowlist") 28load("//:visibility.bzl", "RULES_DEFS_THAT_COMPILE_KOTLIN") 29 30# Intentionally private to prevent misuse. 31_KtCompilerOptInfo = provider( 32 doc = "A restricted set of kotlinc opts", 33 fields = {"opts": "list[string]"}, 34) 35 36_ALLOWED_VISIBILITY_NAMES = [ 37 "__pkg__", 38 "__subpackages__", 39] 40 41def _kt_compiler_opt_impl(ctx): 42 check_compiler_opt_allowlist(ctx.label) 43 44 visibility_groups = [v for v in ctx.attr.visibility if not v.name in _ALLOWED_VISIBILITY_NAMES] 45 if len(visibility_groups) > 0: 46 fail("Using package groups for visibility may expose custom options too broadly: " + str(visibility_groups)) 47 48 return [_KtCompilerOptInfo(opts = ctx.attr.opts)] 49 50kt_compiler_opt = rule( 51 implementation = _kt_compiler_opt_impl, 52 attrs = { 53 "opts": attr.string_list( 54 doc = "The opt(s) this target represents.", 55 mandatory = True, 56 ), 57 }, 58) 59 60def kotlincopts_attrs(): 61 return dict( 62 custom_kotlincopts = attr.label_list( 63 doc = "kt_compiler_opt targets to pass to Kotlin compiler. Most users should not need this attr.", 64 providers = [[_KtCompilerOptInfo]], 65 cfg = "exec", 66 ), 67 ) 68 69def merge_kotlincopts(ctx): 70 """Returns the complete list of opts behind custom_kotlincopts 71 72 Args: 73 ctx: A ctx matching kotlincopts_attrs 74 75 Returns: 76 The list of opts 77 """ 78 custom_opts = [] 79 for target in ctx.attr.custom_kotlincopts: 80 custom_opts.extend(target[_KtCompilerOptInfo].opts) 81 82 return custom_opts 83