-
Notifications
You must be signed in to change notification settings - Fork 4.9k
/
Copy pathplugin.bzl
102 lines (93 loc) · 4.83 KB
/
plugin.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
load("@bazel_skylib//rules:common_settings.bzl", "BuildSettingInfo")
load("@rules_proto//proto:defs.bzl", "ProtoInfo")
# Borrowed from https://github.com/grpc/grpc-java/blob/v1.24.1/java_grpc_library.bzl#L61
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 api_proto_plugin_impl(target, ctx, output_group, mnemonic, output_suffixes):
# Compute output files from the current proto_library node's dependencies.
transitive_outputs = depset(transitive = [dep.output_groups[output_group] for dep in ctx.rule.attr.deps])
proto_sources = target[ProtoInfo].direct_sources
# If this proto_library doesn't actually name any sources, e.g. //api:api,
# but just glues together other libs, we just need to follow the graph.
if not proto_sources:
return [OutputGroupInfo(**{output_group: transitive_outputs})]
# Figure out the set of import paths. Ideally we would use descriptor sets
# built by proto_library, which avoid having to do nasty path mangling, but
# these don't include source_code_info, which we need for comment
# extractions. See https://github.com/bazelbuild/bazel/issues/3971.
import_paths = []
for f in target[ProtoInfo].transitive_sources.to_list():
import_paths.append("{}={}".format(_path_ignoring_repository(f), f.path))
# The outputs live in the ctx.label's package root. We add some additional
# path information to match with protoc's notion of path relative locations.
outputs = []
for output_suffix in output_suffixes:
outputs += [ctx.actions.declare_file(ctx.label.name + "/" + _path_ignoring_repository(f) +
output_suffix) for f in proto_sources]
# Create the protoc command-line args.
inputs = target[ProtoInfo].transitive_sources
ctx_path = ctx.label.package + "/" + ctx.label.name
output_path = outputs[0].root.path + "/" + outputs[0].owner.workspace_root + "/" + ctx_path
args = ["-I./" + ctx.label.workspace_root]
args += ["-I" + import_path for import_path in import_paths]
args += ["--plugin=protoc-gen-api_proto_plugin=" + ctx.executable._api_proto_plugin.path, "--api_proto_plugin_out=" + output_path]
if hasattr(ctx.attr, "_type_db"):
inputs = depset(transitive = [inputs] + [ctx.attr._type_db.files])
if len(ctx.attr._type_db.files.to_list()) != 1:
fail("{} must have one type database file".format(ctx.attr._type_db))
args.append("--api_proto_plugin_opt=type_db_path=" + ctx.attr._type_db.files.to_list()[0].path)
if hasattr(ctx.attr, "_extra_args"):
args.append("--api_proto_plugin_opt=extra_args=" + ctx.attr._extra_args[BuildSettingInfo].value)
args += [src.path for src in target[ProtoInfo].direct_sources]
env = {}
ctx.actions.run(
executable = ctx.executable._protoc,
arguments = args,
inputs = inputs,
tools = [ctx.executable._api_proto_plugin],
outputs = outputs,
mnemonic = mnemonic,
use_default_shell_env = True,
)
transitive_outputs = depset(outputs, transitive = [transitive_outputs])
return [OutputGroupInfo(**{output_group: transitive_outputs})]
def api_proto_plugin_aspect(tool_label, aspect_impl, use_type_db = False):
_attrs = {
"_protoc": attr.label(
default = Label("@com_google_protobuf//:protoc"),
executable = True,
cfg = "exec",
),
"_api_proto_plugin": attr.label(
default = Label(tool_label),
executable = True,
cfg = "exec",
),
}
if use_type_db:
_attrs["_type_db"] = attr.label(
default = Label("@envoy//tools/api_proto_plugin:default_type_db"),
)
_attrs["_extra_args"] = attr.label(
default = Label("@envoy//tools/api_proto_plugin:extra_args"),
)
return aspect(
attr_aspects = ["deps"],
attrs = _attrs,
implementation = aspect_impl,
)