| # Protocol Buffers - Google's data interchange format | 
 | # Copyright 2024 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 | 
 | # | 
 | """Implementation of the proto_lang_toolchain rule.""" | 
 |  | 
 | load("@proto_bazel_features//:features.bzl", "bazel_features") | 
 | load("//bazel/common:proto_common.bzl", "proto_common") | 
 | load("//bazel/common:proto_info.bzl", "ProtoInfo") | 
 | load("//bazel/common:proto_lang_toolchain_info.bzl", "ProtoLangToolchainInfo") | 
 | load("//bazel/private:toolchain_helpers.bzl", "toolchains") | 
 |  | 
 | def _rule_impl(ctx): | 
 |     if ctx.attr.blacklisted_protos and ctx.attr.denylisted_protos: | 
 |         fail("Only one of 'denylisted_protos' and 'blacklisted_protos' can be set (prefer 'denylisted_protos').") | 
 |     denylisted_protos = ctx.attr.denylisted_protos or ctx.attr.blacklisted_protos | 
 |     provided_proto_sources = depset(transitive = [bp[ProtoInfo].transitive_sources for bp in denylisted_protos]).to_list() | 
 |  | 
 |     flag = ctx.attr.command_line | 
 |     if flag.find("$(PLUGIN_OUT)") > -1: | 
 |         fail("in attribute 'command_line': Placeholder '$(PLUGIN_OUT)' is not supported.") | 
 |     flag = flag.replace("$(OUT)", "%s") | 
 |  | 
 |     plugin = None | 
 |     if ctx.attr.plugin != None: | 
 |         plugin = ctx.attr.plugin[DefaultInfo].files_to_run | 
 |  | 
 |     if proto_common.INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION: | 
 |         proto_compiler = ctx.toolchains[toolchains.PROTO_TOOLCHAIN].proto.proto_compiler | 
 |         protoc_opts = ctx.toolchains[toolchains.PROTO_TOOLCHAIN].proto.protoc_opts | 
 |     else: | 
 |         proto_compiler = ctx.attr._proto_compiler.files_to_run | 
 |         protoc_opts = ctx.fragments.proto.experimental_protoc_opts | 
 |  | 
 |     if ctx.attr.protoc_minimal_do_not_use: | 
 |         proto_compiler = ctx.attr.protoc_minimal_do_not_use.files_to_run | 
 |  | 
 |     proto_lang_toolchain_info = ProtoLangToolchainInfo( | 
 |         out_replacement_format_flag = flag, | 
 |         output_files = ctx.attr.output_files, | 
 |         plugin_format_flag = ctx.attr.plugin_format_flag, | 
 |         plugin = plugin, | 
 |         runtime = ctx.attr.runtime, | 
 |         provided_proto_sources = provided_proto_sources, | 
 |         proto_compiler = proto_compiler, | 
 |         protoc_opts = protoc_opts, | 
 |         progress_message = ctx.attr.progress_message, | 
 |         mnemonic = ctx.attr.mnemonic, | 
 |         allowlist_different_package = ctx.attr.allowlist_different_package, | 
 |         toolchain_type = ctx.attr.toolchain_type.label if ctx.attr.toolchain_type else None, | 
 |     ) | 
 |     return [ | 
 |         DefaultInfo(files = depset(), runfiles = ctx.runfiles()), | 
 |         platform_common.ToolchainInfo(proto = proto_lang_toolchain_info), | 
 |         # TODO: remove when --incompatible_enable_proto_toolchains is flipped and removed | 
 |         proto_lang_toolchain_info, | 
 |     ] | 
 |  | 
 | proto_lang_toolchain = rule( | 
 |     _rule_impl, | 
 |     doc = """ | 
 | <p>If using Bazel, please load the rule from <a href="https://github.com/bazelbuild/rules_proto"> | 
 | https://github.com/bazelbuild/rules_proto</a>. | 
 |  | 
 | <p>Specifies how a LANG_proto_library rule (e.g., <code>java_proto_library</code>) should invoke the | 
 | proto-compiler. | 
 | Some LANG_proto_library rules allow specifying which toolchain to use using command-line flags; | 
 | consult their documentation. | 
 |  | 
 | <p>Normally you should not write those kind of rules unless you want to | 
 | tune your Java compiler. | 
 |  | 
 | <p>There's no compiler. The proto-compiler is taken from the proto_library rule we attach to. It is | 
 | passed as a command-line flag to Blaze. | 
 | Several features require a proto-compiler to be invoked on the proto_library rule itself. | 
 | It's beneficial to enforce the compiler that LANG_proto_library uses is the same as the one | 
 | <code>proto_library</code> does. | 
 |  | 
 | <h4>Examples</h4> | 
 |  | 
 | <p>A simple example would be: | 
 | <pre><code class="lang-starlark"> | 
 | proto_lang_toolchain( | 
 |     name = "javalite_toolchain", | 
 |     command_line = "--javalite_out=shared,immutable:$(OUT)", | 
 |     plugin = ":javalite_plugin", | 
 |     runtime = ":protobuf_lite", | 
 | ) | 
 | </code></pre> | 
 |     """, | 
 |     attrs = { | 
 |         "progress_message": attr.string(default = "Generating proto_library %{label}", doc = """ | 
 | This value will be set as the progress message on protoc action."""), | 
 |         "mnemonic": attr.string(default = "GenProto", doc = """ | 
 | This value will be set as the mnemonic on protoc action."""), | 
 |         "command_line": attr.string(mandatory = True, doc = """ | 
 | This value will be passed to proto-compiler to generate the code. Only include the parts | 
 | specific to this code-generator/plugin (e.g., do not include -I parameters) | 
 | <ul> | 
 |   <li><code>$(OUT)</code> is LANG_proto_library-specific. The rules are expected to define | 
 |       how they interpret this variable. For Java, for example, $(OUT) will be replaced with | 
 |       the src-jar filename to create.</li> | 
 | </ul>"""), | 
 |         "output_files": attr.string(values = ["single", "multiple", "legacy"], default = "legacy", doc = """ | 
 | Controls how <code>$(OUT)</code> in <code>command_line</code> is formatted, either by | 
 | a path to a single file or output directory in case of multiple files. | 
 | Possible values are: "single", "multiple"."""), | 
 |         "plugin_format_flag": attr.string(doc = """ | 
 | If provided, this value will be passed to proto-compiler to use the plugin. | 
 | The value must contain a single %s which is replaced with plugin executable. | 
 | <code>--plugin=protoc-gen-PLUGIN=<executable>.</code>"""), | 
 |         "plugin": attr.label( | 
 |             executable = True, | 
 |             cfg = "exec", | 
 |             doc = """ | 
 | If provided, will be made available to the action that calls the proto-compiler, and will be | 
 | passed to the proto-compiler: | 
 | <code>--plugin=protoc-gen-PLUGIN=<executable>.</code>""", | 
 |         ), | 
 |         "runtime": attr.label(doc = """ | 
 | A language-specific library that the generated code is compiled against. | 
 | The exact behavior is LANG_proto_library-specific. | 
 | Java, for example, should compile against the runtime."""), | 
 |         "denylisted_protos": attr.label_list( | 
 |             providers = [ProtoInfo], | 
 |             doc = """ | 
 | No code will be generated for files in the <code>srcs</code> attribute of | 
 | <code>denylisted_protos</code>. | 
 | This is used for .proto files that are already linked into proto runtimes, such as | 
 | <code>any.proto</code>.""", | 
 |         ), | 
 |         # TODO: Remove this once it is safe to do so in OSS. | 
 |         "blacklisted_protos": attr.label_list( | 
 |             providers = [ProtoInfo], | 
 |             doc = """ | 
 | Deprecated. Alias for <code>denylisted_protos</code>. Will be removed in a future release. | 
 | """, | 
 |         ), | 
 |         # TODO: add doc | 
 |         "allowlist_different_package": attr.label( | 
 |             cfg = "exec", | 
 |             providers = [bazel_features.globals.PackageSpecificationInfo] if bazel_features.globals.PackageSpecificationInfo else [], | 
 |         ), | 
 |         # TODO: add doc | 
 |         "toolchain_type": attr.label(), | 
 |         # DO NOT USE. For Protobuf incremental changes only: b/305068148. | 
 |         "protoc_minimal_do_not_use": attr.label( | 
 |             cfg = "exec", | 
 |             executable = True, | 
 |         ), | 
 |     } | ({} if proto_common.INCOMPATIBLE_ENABLE_PROTO_TOOLCHAIN_RESOLUTION else { | 
 |         "_proto_compiler": attr.label( | 
 |             cfg = "exec", | 
 |             executable = True, | 
 |             allow_files = True, | 
 |             default = configuration_field("proto", "proto_compiler"), | 
 |         ), | 
 |     }), | 
 |     provides = [ProtoLangToolchainInfo], | 
 |     fragments = ["proto"], | 
 |     toolchains = toolchains.use_toolchain(toolchains.PROTO_TOOLCHAIN),  # Used to obtain protoc | 
 | ) |