-
Notifications
You must be signed in to change notification settings - Fork 591
/
Copy pathprotobuf.bzl
242 lines (209 loc) · 8.62 KB
/
protobuf.bzl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
load("@bazel_tools//tools/jdk:toolchain_utils.bzl", "find_java_runtime_toolchain", "find_java_toolchain")
load("@rules_proto//proto:defs.bzl", "ProtoInfo")
# Borrowed from https://github.com/grpc/grpc-java/blob/v1.28.0/java_grpc_library.bzl#L59
# "repository" here is for Bazel builds that span multiple WORKSPACES.
def _path_ignoring_repository(f):
# Bazel creates a _virtual_imports directory in case the .proto source files
# need to be accessed at a path that's different from their source path:
# https://github.com/bazelbuild/bazel/blob/0.27.1/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCommon.java#L289
#
# In that case, the import path of the .proto file is the path relative to
# the virtual imports directory of the rule in question.
virtual_imports = "/_virtual_imports/"
if virtual_imports in f.path:
return f.path.split(virtual_imports)[1].split("/", 1)[1]
elif len(f.owner.workspace_root) == 0:
# |f| is in the main repository
return f.short_path
else:
# If |f| is a generated file, it will have "bazel-out/*/genfiles" prefix
# before "external/workspace", so we need to add the starting index of "external/workspace"
return f.path[f.path.find(f.owner.workspace_root) + len(f.owner.workspace_root) + 1:]
def _protoc_cc_output_file(ctx, proto_file):
file_path = proto_file.basename
if proto_file.basename.endswith(".proto"):
file_path = file_path[:-len(".proto")]
return (file_path + ".pb.validate.h", file_path + ".pb.validate.cc")
def _proto_sources(ctx):
protos = []
for dep in ctx.attr.deps:
protos += [f for f in dep[ProtoInfo].direct_sources]
return protos
def _output_dir(ctx):
dir_out = ctx.genfiles_dir.path
if ctx.label.workspace_root:
dir_out += "/" + ctx.label.workspace_root
return dir_out
def _protoc_gen_validate_cc_impl(ctx):
"""Generate C++ protos using protoc-gen-validate plugin"""
flavor = ctx.attr._flavor[BuildSettingInfo].value or ""
protos = _proto_sources(ctx)
out_files = []
for f in protos:
for out in _protoc_cc_output_file(ctx, f):
out_files.append(ctx.actions.declare_file(out, sibling = f))
dir_out = _output_dir(ctx)
args = [
"--validate_out=lang=cc" + flavor + ":" + dir_out,
]
return _protoc_gen_validate_impl(
ctx = ctx,
lang = "cc",
protos = protos,
out_files = out_files,
protoc_args = args,
package_command = "true",
)
def _protoc_gen_validate_impl(ctx, lang, protos, out_files, protoc_args, package_command):
protoc_args.append("--plugin=protoc-gen-validate=" + ctx.executable._plugin.path)
dir_out = ctx.genfiles_dir.path
if ctx.label.workspace_root:
dir_out += "/" + ctx.label.workspace_root
tds = depset([], transitive = [dep[ProtoInfo].transitive_descriptor_sets for dep in ctx.attr.deps])
descriptor_args = [ds.path for ds in tds.to_list()]
if len(descriptor_args) != 0:
protoc_args.append("--descriptor_set_in=%s" % ctx.configuration.host_path_separator.join(descriptor_args))
package_command = package_command.format(dir_out = dir_out)
ctx.actions.run_shell(
outputs = out_files,
inputs = protos + tds.to_list(),
tools = [ctx.executable._plugin, ctx.executable._protoc],
command = " && ".join([
ctx.executable._protoc.path + " $@",
package_command,
]),
arguments = protoc_args + [_path_ignoring_repository(proto) for proto in protos],
mnemonic = "ProtoGenValidate" + lang.capitalize() + "Generate",
use_default_shell_env = True,
)
return DefaultInfo(
files = depset(out_files),
)
cc_proto_gen_validate = rule(
attrs = {
"deps": attr.label_list(
mandatory = True,
providers = [ProtoInfo],
),
"_validate_deps": attr.label_list(
default = [Label("@com_googlesource_code_re2//:re2")],
),
"_protoc": attr.label(
cfg = "host",
default = Label("@com_google_protobuf//:protoc"),
executable = True,
allow_single_file = True,
),
"_plugin": attr.label(
cfg = "host",
default = Label("@com_envoyproxy_protoc_gen_validate//:protoc-gen-validate"),
allow_files = True,
executable = True,
),
"_flavor": attr.label(default = ":template-flavor"),
},
output_to_genfiles = True,
implementation = _protoc_gen_validate_cc_impl,
)
_ProtoValidateSourceInfo = provider(
fields = {
"sources": "Depset of sources created by protoc with protoc-gen-validate plugin",
},
)
def _create_include_path(include):
return "--proto_path={0}={1}".format(_path_ignoring_repository(include), include.path)
def _java_proto_gen_validate_aspect_impl(target, ctx):
proto_info = target[ProtoInfo]
includes = proto_info.transitive_imports
srcs = proto_info.direct_sources
options = ",".join(["lang=java"])
srcjar = ctx.actions.declare_file("%s-validate-gensrc.jar" % ctx.label.name)
args = ctx.actions.args()
args.add(ctx.executable._plugin.path, format = "--plugin=protoc-gen-validate=%s")
args.add("--validate_out={0}:{1}".format(options, srcjar.path))
args.add_all(includes, map_each = _create_include_path)
args.add_all(srcs, map_each = _path_ignoring_repository)
ctx.actions.run(
inputs = depset(transitive = [proto_info.transitive_imports]),
outputs = [srcjar],
executable = ctx.executable._protoc,
arguments = [args],
tools = [ctx.executable._plugin],
progress_message = "Generating %s" % srcjar.path,
)
return [_ProtoValidateSourceInfo(
sources = depset(
[srcjar],
transitive = [dep[_ProtoValidateSourceInfo].sources for dep in ctx.rule.attr.deps],
),
)]
_java_proto_gen_validate_aspect = aspect(
_java_proto_gen_validate_aspect_impl,
provides = [_ProtoValidateSourceInfo],
attr_aspects = ["deps"],
attrs = {
"_protoc": attr.label(
cfg = "host",
default = Label("@com_google_protobuf//:protoc"),
executable = True,
allow_single_file = True,
),
"_plugin": attr.label(
cfg = "host",
default = Label("@com_envoyproxy_protoc_gen_validate//:protoc-gen-validate"),
allow_files = True,
executable = True,
),
},
)
def _java_proto_gen_validate_impl(ctx):
source_jars = [source_jar for dep in ctx.attr.deps for source_jar in dep[_ProtoValidateSourceInfo].sources.to_list()]
deps = [java_common.make_non_strict(dep[JavaInfo]) for dep in ctx.attr.java_deps]
deps += [dep[JavaInfo] for dep in ctx.attr._validate_deps]
java_info = java_common.compile(
ctx,
source_jars = source_jars,
deps = deps,
output_source_jar = ctx.outputs.srcjar,
output = ctx.outputs.jar,
java_toolchain = find_java_toolchain(ctx, ctx.attr._java_toolchain),
)
return [java_info]
"""Bazel rule to create a Java protobuf validation library from proto sources files.
Args:
deps: proto_library rules that contain the necessary .proto files
java_deps: the java_proto_library of the protos being compiled.
"""
java_proto_gen_validate = rule(
attrs = {
"deps": attr.label_list(
providers = [ProtoInfo],
aspects = [_java_proto_gen_validate_aspect],
mandatory = True,
),
"java_deps": attr.label_list(
providers = [JavaInfo],
mandatory = True,
),
"_validate_deps": attr.label_list(
default = [
Label("@com_envoyproxy_protoc_gen_validate//validate:validate_java"),
Label("@com_google_re2j//jar"),
Label("@com_google_protobuf//:protobuf_java"),
Label("@com_google_protobuf//:protobuf_java_util"),
Label("@com_envoyproxy_protoc_gen_validate//java/pgv-java-stub/src/main/java/io/envoyproxy/pgv"),
Label("@com_envoyproxy_protoc_gen_validate//java/pgv-java-validation/src/main/java/io/envoyproxy/pgv"),
],
),
"_java_toolchain": attr.label(default = Label("@bazel_tools//tools/jdk:current_java_toolchain")),
},
fragments = ["java"],
provides = [JavaInfo],
outputs = {
"jar": "lib%{name}.jar",
"srcjar": "lib%{name}-src.jar",
},
implementation = _java_proto_gen_validate_impl,
toolchains = ["@bazel_tools//tools/jdk:toolchain_type"],
)