blob: a8ce86fa6da564a16fcc77c35667be37d39bc6ce [file] [log] [blame]
# Copyright 2022 Google LLC. 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.
"""Combined aspect for all rules_kotlin behaviours that need to traverse exports."""
load(":compiler_plugin.bzl", "kt_compiler_plugin_visitor")
load(":direct_jdeps.bzl", "kt_direct_jdeps_visitor")
load(":forbidden_deps.bzl", "kt_forbidden_deps_visitor")
load(":friend_jars.bzl", "kt_friend_jars_visitor", "kt_friend_labels_visitor")
load(":java_plugin.internal.bzl", "java_plugin_visitor")
# java_xxx_proto_library don't populate java_outputs but we can get them through
# required_aspect_providers from their proto_library deps.
_DEPS_AS_EXPORTS_RULES = [
"java_proto_library",
"java_lite_proto_library",
"java_mutable_proto_library",
]
_NO_SRCS_DEPS_AS_EXPORTS_RULES = [
"proto_library",
]
# visitor = struct[T](
# name = string,
# visit_target = function(Target, ctx.rule): list[T],
# filter_edge = None|(function(src: ?, dest: Target): bool),
# process_unvisited_target = None|(function(Target): list[T]),
# finish_expansion = None|(function(depset[T]): depset[T]),
# )
_VISITORS = [
kt_forbidden_deps_visitor,
kt_direct_jdeps_visitor,
kt_compiler_plugin_visitor,
kt_friend_jars_visitor,
kt_friend_labels_visitor,
java_plugin_visitor,
]
_KtTraverseExportsInfo = provider(
doc = "depsets for transitive info about exports",
fields = {
v.name: ("depset[%s]" % v.name)
for v in _VISITORS
},
)
_EMPTY_KT_TRAVERSE_EXPORTS_INFO = _KtTraverseExportsInfo(**{
v.name: depset()
for v in _VISITORS
})
def _aspect_impl(target, ctx):
if not (JavaInfo in target):
# Ignore non-JVM targets. This also chops-up the
# traversal domain at these targets.
# TODO: Support non-JVM targets for KMP
return _EMPTY_KT_TRAVERSE_EXPORTS_INFO
exports = []
exports.extend(getattr(ctx.rule.attr, "exports", [])) # exports list is frozen
if ctx.rule.kind in _DEPS_AS_EXPORTS_RULES:
exports.extend(ctx.rule.attr.deps)
elif ctx.rule.kind in _NO_SRCS_DEPS_AS_EXPORTS_RULES and not ctx.rule.attr.srcs:
exports.extend(ctx.rule.attr.deps)
return _KtTraverseExportsInfo(**{
v.name: depset(
direct = v.visit_target(target, ctx.rule),
transitive = [
getattr(e[_KtTraverseExportsInfo], v.name)
for e in exports
if (not v.filter_edge or v.filter_edge(target, e))
],
)
for v in _VISITORS
})
_aspect = aspect(
implementation = _aspect_impl,
provides = [_KtTraverseExportsInfo],
# Transitively check exports, since they are effectively directly depended on.
# "deps" needed for rules that treat deps as exports (usually absent srcs).
attr_aspects = ["exports", "deps"],
required_aspect_providers = [JavaInfo], # to get at JavaXxxProtoAspects' JavaInfos
)
def _create_visitor_expand(visitor):
def _visitor_expand(targets, root = None):
direct = []
transitive = []
for t in targets:
if (not visitor.filter_edge or visitor.filter_edge(root, t)):
if _KtTraverseExportsInfo in t:
transitive.append(getattr(t[_KtTraverseExportsInfo], visitor.name))
elif visitor.process_unvisited_target:
direct.extend(visitor.process_unvisited_target(t))
expanded_set = depset(direct = direct, transitive = transitive)
return visitor.finish_expansion(expanded_set) if visitor.finish_expansion else expanded_set
return _visitor_expand
kt_traverse_exports = struct(
aspect = _aspect,
**{
"expand_" + v.name: _create_visitor_expand(v)
for v in _VISITORS
}
)