1load("@com_envoyproxy_protoc_gen_validate//bazel:pgv_proto_library.bzl", "pgv_cc_proto_library")
2load("@com_google_protobuf//:protobuf.bzl", _py_proto_library = "py_proto_library")
3load("@io_bazel_rules_go//go:def.bzl", "go_test")
4load("@io_bazel_rules_go//proto:def.bzl", "go_grpc_library", "go_proto_library")
5load("@rules_proto//proto:defs.bzl", "proto_library")
6load(
7    "//bazel:external_proto_deps.bzl",
8    "EXTERNAL_PROTO_CC_BAZEL_DEP_MAP",
9    "EXTERNAL_PROTO_GO_BAZEL_DEP_MAP",
10    "EXTERNAL_PROTO_PY_BAZEL_DEP_MAP",
11)
12
13_PY_PROTO_SUFFIX = "_py_proto"
14_CC_PROTO_SUFFIX = "_cc_proto"
15_CC_GRPC_SUFFIX = "_cc_grpc"
16_GO_PROTO_SUFFIX = "_go_proto"
17_GO_IMPORTPATH_PREFIX = "github.com/cncf/xds/go/"
18
19_COMMON_PROTO_DEPS = [
20    "@com_google_protobuf//:any_proto",
21    "@com_google_protobuf//:descriptor_proto",
22    "@com_google_protobuf//:duration_proto",
23    "@com_google_protobuf//:empty_proto",
24    "@com_google_protobuf//:struct_proto",
25    "@com_google_protobuf//:timestamp_proto",
26    "@com_google_protobuf//:wrappers_proto",
27    "@com_google_googleapis//google/api:http_proto",
28    "@com_google_googleapis//google/api:annotations_proto",
29    "@com_google_googleapis//google/rpc:status_proto",
30    "@com_envoyproxy_protoc_gen_validate//validate:validate_proto",
31]
32
33def _proto_mapping(dep, proto_dep_map, proto_suffix):
34    mapped = proto_dep_map.get(dep)
35    if mapped == None:
36        prefix = "@" + Label(dep).workspace_name if not dep.startswith("//") else ""
37        return prefix + "//" + Label(dep).package + ":" + Label(dep).name + proto_suffix
38    return mapped
39
40def _go_proto_mapping(dep):
41    return _proto_mapping(dep, EXTERNAL_PROTO_GO_BAZEL_DEP_MAP, _GO_PROTO_SUFFIX)
42
43def _cc_proto_mapping(dep):
44    return _proto_mapping(dep, EXTERNAL_PROTO_CC_BAZEL_DEP_MAP, _CC_PROTO_SUFFIX)
45
46def _py_proto_mapping(dep):
47    return _proto_mapping(dep, EXTERNAL_PROTO_PY_BAZEL_DEP_MAP, _PY_PROTO_SUFFIX)
48
49# TODO(htuch): Convert this to native py_proto_library once
50# https://github.com/bazelbuild/bazel/issues/3935 and/or
51# https://github.com/bazelbuild/bazel/issues/2626 are resolved.
52def _xds_py_proto_library(name, srcs = [], deps = []):
53    mapped_deps = [_py_proto_mapping(dep) for dep in deps]
54    mapped_unique_deps = []
55    [mapped_unique_deps.append(d) for d in mapped_deps if d not in mapped_unique_deps]
56    _py_proto_library(
57        name = name + _PY_PROTO_SUFFIX,
58        srcs = srcs,
59        default_runtime = "@com_google_protobuf//:protobuf_python",
60        protoc = "@com_google_protobuf//:protoc",
61        deps = mapped_unique_deps + [
62            "@com_envoyproxy_protoc_gen_validate//validate:validate_py",
63            "@com_google_googleapis//google/rpc:status_py_proto",
64            "@com_google_googleapis//google/api:annotations_py_proto",
65            "@com_google_googleapis//google/api:http_py_proto",
66            "@com_google_googleapis//google/api:httpbody_py_proto",
67        ],
68        visibility = ["//visibility:public"],
69    )
70
71# This defines googleapis py_proto_library. The repository does not provide its definition and requires
72# overriding it in the consuming project (see https://github.com/grpc/grpc/issues/19255 for more details).
73def py_proto_library(name, deps = [], plugin = None):
74    srcs = [dep[:-6] + ".proto" if dep.endswith("_proto") else dep for dep in deps]
75    proto_deps = []
76
77    # py_proto_library in googleapis specifies *_proto rules in dependencies.
78    # By rewriting *_proto to *.proto above, the dependencies in *_proto rules are not preserved.
79    # As a workaround, manually specify the proto dependencies for the imported python rules.
80    if name == "annotations_py_proto":
81        proto_deps = proto_deps + [":http_py_proto"]
82
83    # checked.proto depends on syntax.proto, we have to add this dependency manually as well.
84    if name == "checked_py_proto":
85        proto_deps = proto_deps + [":syntax_py_proto"]
86
87    # Special handling for expr_proto target
88    if srcs[0] == ":expr_moved.proto":
89        srcs = ["checked.proto", "eval.proto", "explain.proto", "syntax.proto", "value.proto",]
90        proto_deps = proto_deps + ["@com_google_googleapis//google/rpc:status_py_proto"]
91
92
93    # py_proto_library does not support plugin as an argument yet at gRPC v1.25.0:
94    # https://github.com/grpc/grpc/blob/v1.25.0/bazel/python_rules.bzl#L72.
95    # plugin should also be passed in here when gRPC version is greater than v1.25.x.
96    _py_proto_library(
97        name = name,
98        srcs = srcs,
99        default_runtime = "@com_google_protobuf//:protobuf_python",
100        protoc = "@com_google_protobuf//:protoc",
101        deps = proto_deps + ["@com_google_protobuf//:protobuf_python"],
102        visibility = ["//visibility:public"],
103    )
104
105def _xds_cc_py_proto_library(
106        name,
107        visibility = ["//visibility:private"],
108        srcs = [],
109        deps = [],
110        linkstatic = 0,
111        has_services = 0):
112    relative_name = ":" + name
113    proto_library(
114        name = name,
115        srcs = srcs,
116        deps = deps + _COMMON_PROTO_DEPS,
117        visibility = visibility,
118    )
119    cc_proto_library_name = name + _CC_PROTO_SUFFIX
120    pgv_cc_proto_library(
121        name = cc_proto_library_name,
122        linkstatic = linkstatic,
123        cc_deps = [_cc_proto_mapping(dep) for dep in deps] + [
124            "@com_google_googleapis//google/api:http_cc_proto",
125            "@com_google_googleapis//google/api:httpbody_cc_proto",
126            "@com_google_googleapis//google/api:annotations_cc_proto",
127            "@com_google_googleapis//google/rpc:status_cc_proto",
128        ],
129        deps = [relative_name],
130        visibility = ["//visibility:public"],
131    )
132    _xds_py_proto_library(name, srcs, deps)
133
134    # Optionally define gRPC services
135    if has_services:
136        # TODO: neither C++ or Python service generation is supported today, follow the Envoy example to implementthis.
137        pass
138
139def xds_proto_package(
140        name = "pkg",
141        srcs = [],
142        deps = [],
143        has_services = False,
144        visibility = ["//visibility:public"]):
145    if srcs == []:
146        srcs = native.glob(["*.proto"])
147
148    name = "pkg"
149    _xds_cc_py_proto_library(
150        name = name,
151        visibility = visibility,
152        srcs = srcs,
153        deps = deps,
154        has_services = has_services,
155    )
156
157    compilers = ["@io_bazel_rules_go//proto:go_proto", "//bazel:pgv_plugin_go"]
158    if has_services:
159        compilers = ["@io_bazel_rules_go//proto:go_grpc", "//bazel:pgv_plugin_go"]
160
161    # Because RBAC proro depends on googleapis syntax.proto and checked.proto,
162    # which share the same go proto library, it causes duplicative dependencies.
163    # Thus, we use depset().to_list() to remove duplicated depenencies.
164    go_proto_library(
165        name = name + _GO_PROTO_SUFFIX,
166        compilers = compilers,
167        importpath = _GO_IMPORTPATH_PREFIX + native.package_name(),
168        proto = name,
169        visibility = ["//visibility:public"],
170        deps = depset([_go_proto_mapping(dep) for dep in deps] + [
171            "@com_envoyproxy_protoc_gen_validate//validate:go_default_library",
172            "@com_github_golang_protobuf//ptypes:go_default_library_gen",
173            "@go_googleapis//google/api:annotations_go_proto",
174            "@go_googleapis//google/rpc:status_go_proto",
175            "@io_bazel_rules_go//proto/wkt:any_go_proto",
176            "@io_bazel_rules_go//proto/wkt:duration_go_proto",
177            "@io_bazel_rules_go//proto/wkt:struct_go_proto",
178            "@io_bazel_rules_go//proto/wkt:timestamp_go_proto",
179            "@io_bazel_rules_go//proto/wkt:wrappers_go_proto",
180        ]).to_list(),
181    )
182
183def xds_cc_test(name, **kwargs):
184    native.cc_test(
185        name = name,
186        **kwargs
187    )
188
189def xds_go_test(name, **kwargs):
190    go_test(
191        name = name,
192        **kwargs
193    )
194
195# Old names for backward compatibility.
196# TODO(roth): Remove these once all callers are migrated to the new names.
197def udpa_proto_package(srcs = [], deps = [], has_services = False, visibility = ["//visibility:public"]):
198  xds_proto_package(srcs=srcs, deps=deps, has_services=has_services, visibility=visibility)
199
200def udpa_cc_test(name, **kwargs):
201  xds_cc_test(name, **kwargs)
202
203def udpa_go_test(name, **kwargs):
204  xds_go_test(name, **kwargs)
205