blob: 2977c115f9374ec19d573d529be4d2a15efca9d4 [file]
# Copyright 2024 The Pigweed Authors
#
# 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
#
# https://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.
"""A filegroup grouping .proto and .options files."""
PwProtoOptionsInfo = provider(
"Allows `pw_proto_filegroup` targets to pass along `.options` files " +
"without polluting the `DefaultInfo` provider, which means they can " +
"still be used in the `srcs` of `proto_library` targets.",
fields = {
"options_files": (".options file(s) associated with a proto_library " +
"for Pigweed codegen."),
},
)
def _pw_proto_filegroup_impl(ctx):
source_files = list()
options_files = list()
for src in ctx.attr.srcs:
source_files += src.files.to_list()
for options_src in ctx.attr.options_files:
for file in options_src.files.to_list():
if file.extension == "options" or file.extension == "pwpb_options":
options_files.append(file)
else:
fail((
"Files provided as `options_files` to a " +
"`pw_proto_filegroup` must have the `.options` or " +
"`.pwpb_options` extensions; the file `{}` was provided."
).format(file.basename))
return [
DefaultInfo(files = depset(source_files)),
PwProtoOptionsInfo(options_files = depset(options_files)),
]
pw_proto_filegroup = rule(
doc = (
"Acts like a `filegroup`, but with an additional `options_files` " +
"attribute that accepts a list of `.options` files. These `.options` " +
"files should typically correspond to `.proto` files provided under " +
"the `srcs` attribute." +
"\n\n" +
"A `pw_proto_filegroup` is intended to be passed into the `srcs` of " +
"a `proto_library` target as if it were a normal `filegroup` " +
"containing only `.proto` files. For the purposes of the " +
"`proto_library` itself, the `pw_proto_filegroup` does indeed act " +
"just like a normal `filegroup`; the `options_files` attribute is " +
"ignored. However, if that `proto_library` target is then passed " +
"(directly or transitively) into the `deps` of a `pw_proto_library` " +
"for code generation, the `pw_proto_library` target will have access " +
"to the provided `.options` files and will pass them to the code " +
"generator." +
"\n\n" +
"Note that, in order for a `pw_proto_filegroup` to be a valid `srcs` " +
"entry for a `proto_library`, it must meet the same conditions " +
"required of a standard `filegroup` in that context. Namely, its " +
"`srcs` must provide at least one `.proto` (or `.protodevel`) file. " +
"Put simply, a `pw_proto_filegroup` cannot be used as a vector for " +
"injecting solely `.options` files; it must contain at least one " +
"proto as well (generally one associated with an included `.options` " +
"file in the interest of clarity)." +
"\n\n" +
"Regarding the somewhat unusual usage, this feature's design was " +
"mostly preordained by the combination of Bazel's strict access " +
"controls, the restrictions imposed on inputs to the `proto_library` " +
"rule, and the need to support `.options` files from transitive " +
"dependencies."
),
implementation = _pw_proto_filegroup_impl,
attrs = {
"options_files": attr.label_list(
allow_files = True,
),
"srcs": attr.label_list(
allow_files = True,
),
},
provides = [PwProtoOptionsInfo],
)