xref: /aosp_15_r20/build/bazel/rules/python/py_proto.bzl (revision 7594170e27e0732bc44b93d1440d87a54b6ffe7c)
1*7594170eSAndroid Build Coastguard Worker# Copyright (C) 2022 The Android Open Source Project
2*7594170eSAndroid Build Coastguard Worker#
3*7594170eSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
4*7594170eSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
5*7594170eSAndroid Build Coastguard Worker# You may obtain a copy of the License at
6*7594170eSAndroid Build Coastguard Worker#
7*7594170eSAndroid Build Coastguard Worker#     http://www.apache.org/licenses/LICENSE-2.0
8*7594170eSAndroid Build Coastguard Worker#
9*7594170eSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
10*7594170eSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
11*7594170eSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*7594170eSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
13*7594170eSAndroid Build Coastguard Worker# limitations under the License.
14*7594170eSAndroid Build Coastguard Worker
15*7594170eSAndroid Build Coastguard Workerload("@bazel_skylib//lib:paths.bzl", "paths")
16*7594170eSAndroid Build Coastguard Workerload("//build/bazel/rules:proto_file_utils.bzl", "proto_file_utils")
17*7594170eSAndroid Build Coastguard Worker
18*7594170eSAndroid Build Coastguard Worker_TYPE_DICTIONARY = {".py": "_pb2.py"}
19*7594170eSAndroid Build Coastguard Worker
20*7594170eSAndroid Build Coastguard Workerdef _py_proto_sources_gen_rule_impl(ctx):
21*7594170eSAndroid Build Coastguard Worker    out_files_map = proto_file_utils.generate_proto_action(
22*7594170eSAndroid Build Coastguard Worker        proto_infos = [dep[ProtoInfo] for dep in ctx.attr.deps],
23*7594170eSAndroid Build Coastguard Worker        protoc = ctx.executable._protoc,
24*7594170eSAndroid Build Coastguard Worker        ctx = ctx,
25*7594170eSAndroid Build Coastguard Worker        type_dictionary = _TYPE_DICTIONARY,
26*7594170eSAndroid Build Coastguard Worker        out_flags = [],
27*7594170eSAndroid Build Coastguard Worker        plugin_executable = None,
28*7594170eSAndroid Build Coastguard Worker        out_arg = "--python_out",
29*7594170eSAndroid Build Coastguard Worker        mnemonic = "PyProtoGen",
30*7594170eSAndroid Build Coastguard Worker        transitive_proto_infos = [dep[ProtoInfo] for dep in ctx.attr.transitive_deps],
31*7594170eSAndroid Build Coastguard Worker    )
32*7594170eSAndroid Build Coastguard Worker
33*7594170eSAndroid Build Coastguard Worker    # proto_file_utils generates the files at <package>/<label>
34*7594170eSAndroid Build Coastguard Worker    # interesting examples
35*7594170eSAndroid Build Coastguard Worker    # 1. foo.proto will be generated in <package>/<label>/foo_pb2.py
36*7594170eSAndroid Build Coastguard Worker    # 2. foo.proto with an import prefix in proto_library will be generated in <package>/<label>/<import_prefix>/foo_pb2.py
37*7594170eSAndroid Build Coastguard Worker    imports = [paths.join("__main__", ctx.label.package, ctx.label.name)]
38*7594170eSAndroid Build Coastguard Worker
39*7594170eSAndroid Build Coastguard Worker    output_depset = depset(direct = out_files_map[".py"])
40*7594170eSAndroid Build Coastguard Worker
41*7594170eSAndroid Build Coastguard Worker    return [
42*7594170eSAndroid Build Coastguard Worker        DefaultInfo(files = output_depset),
43*7594170eSAndroid Build Coastguard Worker        PyInfo(
44*7594170eSAndroid Build Coastguard Worker            transitive_sources = output_depset,
45*7594170eSAndroid Build Coastguard Worker            imports = depset(direct = imports),
46*7594170eSAndroid Build Coastguard Worker        ),
47*7594170eSAndroid Build Coastguard Worker    ]
48*7594170eSAndroid Build Coastguard Worker
49*7594170eSAndroid Build Coastguard Worker_py_proto_sources_gen = rule(
50*7594170eSAndroid Build Coastguard Worker    implementation = _py_proto_sources_gen_rule_impl,
51*7594170eSAndroid Build Coastguard Worker    attrs = {
52*7594170eSAndroid Build Coastguard Worker        "deps": attr.label_list(
53*7594170eSAndroid Build Coastguard Worker            providers = [ProtoInfo],
54*7594170eSAndroid Build Coastguard Worker            doc = "proto_library or any other target exposing ProtoInfo provider with *.proto files",
55*7594170eSAndroid Build Coastguard Worker            mandatory = True,
56*7594170eSAndroid Build Coastguard Worker        ),
57*7594170eSAndroid Build Coastguard Worker        "transitive_deps": attr.label_list(
58*7594170eSAndroid Build Coastguard Worker            providers = [ProtoInfo],
59*7594170eSAndroid Build Coastguard Worker            doc = """
60*7594170eSAndroid Build Coastguard Workerproto_library that will be added to aprotoc -I when compiling the direct .proto sources.
61*7594170eSAndroid Build Coastguard WorkerWARNING: This is an experimental attribute and is expected to be deprecated in the future.
62*7594170eSAndroid Build Coastguard Worker""",
63*7594170eSAndroid Build Coastguard Worker        ),
64*7594170eSAndroid Build Coastguard Worker        "_protoc": attr.label(
65*7594170eSAndroid Build Coastguard Worker            default = Label("//external/protobuf:aprotoc"),
66*7594170eSAndroid Build Coastguard Worker            executable = True,
67*7594170eSAndroid Build Coastguard Worker            cfg = "exec",
68*7594170eSAndroid Build Coastguard Worker        ),
69*7594170eSAndroid Build Coastguard Worker    },
70*7594170eSAndroid Build Coastguard Worker)
71*7594170eSAndroid Build Coastguard Worker
72*7594170eSAndroid Build Coastguard Workerdef py_proto_library(
73*7594170eSAndroid Build Coastguard Worker        name,
74*7594170eSAndroid Build Coastguard Worker        deps = [],
75*7594170eSAndroid Build Coastguard Worker        transitive_deps = [],
76*7594170eSAndroid Build Coastguard Worker        target_compatible_with = [],
77*7594170eSAndroid Build Coastguard Worker        data = [],
78*7594170eSAndroid Build Coastguard Worker        **kwargs):
79*7594170eSAndroid Build Coastguard Worker    proto_lib_name = name + "_proto_gen"
80*7594170eSAndroid Build Coastguard Worker
81*7594170eSAndroid Build Coastguard Worker    _py_proto_sources_gen(
82*7594170eSAndroid Build Coastguard Worker        name = proto_lib_name,
83*7594170eSAndroid Build Coastguard Worker        deps = deps,
84*7594170eSAndroid Build Coastguard Worker        transitive_deps = transitive_deps,
85*7594170eSAndroid Build Coastguard Worker        **kwargs
86*7594170eSAndroid Build Coastguard Worker    )
87*7594170eSAndroid Build Coastguard Worker
88*7594170eSAndroid Build Coastguard Worker    # There may be a better way to do this, but proto_lib_name appears in both srcs
89*7594170eSAndroid Build Coastguard Worker    # and deps because it must appear in srcs to cause the protobuf files to
90*7594170eSAndroid Build Coastguard Worker    # actually be compiled, and it must appear in deps for the PyInfo provider to
91*7594170eSAndroid Build Coastguard Worker    # be respected and the "imports" path to be included in this library.
92*7594170eSAndroid Build Coastguard Worker    native.py_library(
93*7594170eSAndroid Build Coastguard Worker        name = name,
94*7594170eSAndroid Build Coastguard Worker        srcs = [":" + proto_lib_name],
95*7594170eSAndroid Build Coastguard Worker        deps = [":" + proto_lib_name] + (["//external/protobuf:libprotobuf-python"] if "libprotobuf-python" not in name else []),
96*7594170eSAndroid Build Coastguard Worker        data = data,
97*7594170eSAndroid Build Coastguard Worker        target_compatible_with = target_compatible_with,
98*7594170eSAndroid Build Coastguard Worker        **kwargs
99*7594170eSAndroid Build Coastguard Worker    )
100